Я пытаюсь создать оболочку JNI для этого приложения Windows под названием «Личная связь» через предоставленный им COM-объект. Справка PCOM
Благодаря большому количеству поисков, я справился со многими самостоятельно. Я могу достаточно подключиться к COM-объекту и запустить методы получения / установки для получения различной информации о приложении.
Моя проблема теперь связана с объектами Sink (пытаюсь заставить приложение отправлять мне события).
Насколько я могу судить, все возвращает хороший код возврата, но Invoke для класса Sink никогда не вызывается. Что еще хуже, если событие должно было быть вызвано, при освобождении COM-объекта, который сказал ему начать отправку событий, приложение зависает. Если я заканчиваю приложение, сообщая о приемнике, но не заставляя его запускать какие-либо события, приложение не зависает.
Я пробовал различные методы и компиляторы. Все они дают одинаковый результат. Что странно, хотя, если я использую тот же код в реальном приложении (exe) за пределами Java, все работает нормально, и события запускаются через объект Sink. Так что я действительно растерялся из-за того, что не так с Java на картинке.
Вот мой код, который у меня есть:
PcommControl.h (My Wrapper для управления COM)
initConnectionManagerEvents: создает новый объект приемника и сообщает о нем COM. RegisterStartEvent указывает COM начать отправку сообщений в объекты приемника.
removeConnectionManagerEvents: исключает и удаляет все объекты-приемники. UnregisterStartEvent указывает COM прекратить отправку сообщений в объекты приемника.
jobject PcommControl::initConnectionManagerEvents(jobject sinkType) {
if (!initConnectionManager())
return NULL;
if (autConnectionManagerPoint == NULL) {
autConnectionManagerPoint = getConnectionPoint(autConnectionManager,
DIID_IStartEvent);
if (autConnectionManagerPoint == NULL)
return NULL;
}
ConnectionSink *conSinkC = new ConnectionSink(jvm, sinkType);
if (!conSinkC->isInitialized()) {
delete conSinkC;
return NULL;
}
if (!conSinkC->Advise(autConnectionManagerPoint)) {
#ifdef DEBUG
printf("PcommControl: failed to advise ConnectionManagerEvent\n");
#endif
delete conSinkC;
return NULL;
}
#ifdef DEBUG
printf("PcommControl: ConnectionManagerEvent> %ld\n", conSinkC->getCookie());
#endif
ConnectionSink *temp = connectionManagerEvents.put(
(long) conSinkC->getCookie(), conSinkC);
if (temp) {
temp->Release();
}
if (connectionManagerEvents.getSize() == 1) {
#ifdef DEBUG
printf("PcommControl: Registering ConnectionManagerEvent\n");
#endif
HRESULT hresult = autConnectionManager->RegisterStartEvent();
if (!SUCCEEDED(hresult)) {
#ifdef DEBUG
printf("Failed to get RegisterStartEvent\n");
#endif
// TODO
}
}
return conSinkC->getJavaObjectConnection();
}
void PcommControl::removeConnectionManagerEvents() {
ConnectionSink *connectionSink;
if ((autConnectionManager) && (!safeUnload)) {
#ifdef DEBUG
printf("PcommControl: Unregistering ConnectionManagerEvent\n");
#endif
// TODO: seems to cause hanging issues for Java
HRESULT hresult = autConnectionManager->UnregisterStartEvent();
if (!SUCCEEDED(hresult)) {
#ifdef DEBUG
printf("Failed to UnregisterStartEvent\n");
#endif
}
}
while ((connectionSink = connectionManagerEvents.removeHead()) != NULL) {
if (!safeUnload) {
#ifdef DEBUG
printf("PcommControl: releasing a connection manager event\n");
#endif
connectionSink->Unadvise();
#ifdef DEBUG
printf("PcommControl: start release\n");
#endif
connectionSink->Release();
}
}
#ifdef DEBUG
printf("PcommControl: done releasing ConnectionManager events\n");
#endif
}
JNIEventSink.h (Интерфейс Мой Мойки для всех Мойок JNI)
#ifndef JNIEVENTSINK_H_
#define JNIEVENTSINK_H_
#include <jni.h>
#include <OCIdl.h>
#define FARFAR FAR* FAR*
class JNIEventSink: public IDispatch {
protected:
private:
bool initialized;
bool deconstructor;
DWORD referenceCount;
JavaVM *jvm;
jobject javaObjectConnection;
DWORD cookie;
IConnectionPoint *point;
static jclass javaLangClass;
static jmethodID javaLangClassNewInstance;
void init(JavaVM *javaVM, jobject sinkType) {
initialized = false;
deconstructor = false;
referenceCount = 0;
jvm = javaVM;
javaObjectConnection = NULL;
cookie = 0;
AddRef();
// create Java sink class from sinkType
// if (javaVM) {
// JNIEnv *env;
// javaVM->AttachCurrentThread((void **) &env, NULL);
// if (env == NULL) {
//#ifdef DEBUG
// printf("JNIEventSink: java environment not found!\n");
//#endif
// return;
// }
//
// if (javaLangClass == NULL) {
// javaLangClass = NULL;
// javaLangClassNewInstance = NULL;
//
// javaLangClass = env->FindClass("java/lang/Class");
// if (javaLangClass == NULL) {
//#ifdef DEBUG
// printf("JNIEventSink: javaLangClass not found!\n");
//#endif
// return;
// }
// javaLangClassNewInstance = env->GetMethodID(javaLangClass,
// "newInstance", "()Ljava/lang/Object;");
// if (javaLangClassNewInstance == NULL) {
//#ifdef DEBUG
// printf(
// "JNIEventSink: javaLangClass NewInstance not found!\n");
//#endif
// return;
// }
// }
//
// javaObjectConnection = env->CallObjectMethod(sinkType,
// javaLangClassNewInstance);
// if (javaObjectConnection == NULL) {
//#ifdef DEBUG
// printf(
// "JNIEventSink: Failed to create new Connection Object!\n");
//#endif
// return;
// }
// }
initialized = true;
}
public:
bool test;
JNIEventSink(JavaVM *javaVM, jobject sinkType) {
#ifdef DEBUG
printf("JNIEventSink: constructor\n");
#endif
init(javaVM, sinkType);
test = false;
}
virtual ~JNIEventSink() {
#ifdef DEBUG
printf("JNIEventSink: deconstructor\n");
if (test)
printf("YESYESYESYESYESYESYESYES\n");
#endif
deconstructor = true;
//
// if (point != NULL)
// Unadvise();
//
// if (referenceCount > 0)
// Release();
}
bool isInitialized() {
return initialized;
}
bool Advise(IConnectionPoint *point) {
#ifdef DEBUG
printf("JNIEventSink: Start Advise\n");
#endif
this->point = point;
this->point->AddRef();
HRESULT hresult = point->Advise(this, &cookie);
// TODO set cookie to java class
#ifdef DEBUG
printf("JNIEventSink: Advise End\n");
if (!SUCCEEDED(hresult))
printf("JNIEventSink: failed\n");
#endif
return SUCCEEDED(hresult);
}
bool Unadvise() {
#ifdef DEBUG
printf("JNIEventSink: Start Unadvise\n");
#endif
if (point == NULL)
return true;
IConnectionPoint *point = this->point;
this->point = NULL;
HRESULT hresult = point->Unadvise(cookie);
point->Release();
#ifdef DEBUG
printf("JNIEventSink: Unadvise End\n");
if (!SUCCEEDED(hresult))
printf("JNIEventSink: failed\n");
#endif
return SUCCEEDED(hresult);
}
DWORD getCookie() {
return cookie;
}
jobject getJavaObjectConnection() {
return javaObjectConnection;
}
ULONG
STDMETHODCALLTYPE AddRef() {
#ifdef DEBUG
printf("JNIEventSink: Add Ref %ld,%ld,%ld\n", (long) this, cookie,
referenceCount);
#endif
referenceCount++;
return referenceCount;
}
ULONG
STDMETHODCALLTYPE Release() {
#ifdef DEBUG
printf("JNIEventSink: Start Release %ld,%ld,%ld\n", (long) this,
cookie, referenceCount);
#endif
if (referenceCount == 0) {
#ifdef DEBUG
printf("0 ref\n");
#endif
return 0;
}
referenceCount--;
long temp = referenceCount;
if ((temp == 0) && (!deconstructor)) {
#ifdef DEBUG
printf("JNIEventSink: deleting\n");
#endif
delete this;
}
return temp;
}
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
void **ppvObject) {
#ifdef DEBUG
printf("JNIEventSink: QueryInterface %ld,%ld\n", (long) this, cookie);
#endif
if (iid == IID_IUnknown) {
*ppvObject = (IUnknown *) this;
} else if (iid == IID_IDispatch) {
*ppvObject = (IDispatch *) this;
} else {
*ppvObject = (void *) this;
}
((IUnknown *) (*ppvObject))->AddRef();
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) {
#ifdef DEBUG
printf("JNIEventSink: GetTypeInfoCount %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) {
#ifdef DEBUG
printf("JNIEventSink: GetIDsOfNames %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo,
LCID lcid, ITypeInfo FARFAR ppTInfo) {
#ifdef DEBUG
printf("JNIEventSink: GetTypeInfo %ld,%ld\n", (long) this, cookie);
#endif
return E_NOTIMPL;
}
// virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
// LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams,
// VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo,
// unsigned int FAR* puArgErr) = 0;
};
jclass JNIEventSink::javaLangClass = NULL;
jmethodID JNIEventSink::javaLangClassNewInstance = NULL;
#endif /* JNIEVENTSINK_H_ */
ConnectionSink.h (Моя реализация JNI Sink, которая предполагает получение всех событий из autConnectionManager)
#ifndef CONNECTIONSINK_H_
#define CONNECTIONSINK_H_
#include <jni.h>
#include "PcommInterfaces.h"
#include "..\COM\JNIEventSink.h"
class ConnectionSink: public JNIEventSink {
private:
public:
ConnectionSink(JavaVM *javaVM, jobject sinkType) :
JNIEventSink(javaVM, sinkType) {
}
virtual ~ConnectionSink() {
#ifdef DEBUG
printf("ConnectionSink: deconstructor\n");
#endif
}
// IStartEvent
// future events I want to call
// 1 - void NotifyStartEvent(VARIANT ConnHandle, VARIANT_BOOL bStarted);
// 2 - void NotifyStartError(VARIANT ConnHandle);
// 3 - void NotifyStartStop(int* Reason);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo,
unsigned int FAR* puArgErr) {
// TODO this seems like it is never called
#ifdef DEBUG
printf("ConnectionSink: Invoke %ld,%ld,%ld\n", (long) this,
this->getCookie(), dispIdMember);
#endif
test = true;
return S_OK;
//return E_NOTIMPL;
}
};
#endif /* CONNECTIONSINK_H_ */
Пример вывода при зависании:
Java_gov_ssa_utils_pcomm_ConnectionManager_registerStartEvents
JNIEventSink: constructor
JNIEventSink: Add Ref 72880304,0,0
JNIEventSink: Start Advise
JNIEventSink: Add Ref 72880304,0,1
JNIEventSink: Advise End
PcommControl: ConnectionManagerEvent> 1
PcommControl: Registering ConnectionManagerEvent
Created and attached sink.
Waiting 10 seconds for user to fire event
Destroying.
Java_gov_ssa_utils_PComm_release
PcommControl: destroying
PcommControl: Unregistering ConnectionManagerEvent
Спасибо за любую помощь.