diff --git a/jni/CallbackProxy.cpp b/jni/CallbackProxy.cpp new file mode 100644 index 0000000..6b2cc42 --- /dev/null +++ b/jni/CallbackProxy.cpp @@ -0,0 +1,888 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "CallbackProxy.h" +#include "Variant.h" + +// hook myself up as a listener for delegate +CallbackProxy::CallbackProxy(JNIEnv *env, + jobject aSinkObj) : + // initialize some variables + m_cRef(0), MethNum(0), MethName(NULL), MethID(NULL) +{ + // keep a pointer to the sink + javaSinkObj = env->NewGlobalRef(aSinkObj); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + + // we need this to attach to the event invocation thread + env->GetJavaVM(&jvm); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + AddRef(); +} + +// unhook myself up as a listener and get rid of delegate +CallbackProxy::~CallbackProxy() +{ + JNIEnv *env; + jint vmConnectionStatus = JNI_EVERSION ; + jint attachReturnStatus = -1; // AttachCurrentThread return status.. negative numbers are failure return codes. + + // attach to the current running thread -- JDK 1.4 jni.h has two param cover for 3 param call + vmConnectionStatus = jvm->GetEnv((void **)&env, JNI_VERSION_1_2); + if ((env != NULL)&& env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + if (vmConnectionStatus == JNI_EDETACHED){ + //printf("Unhook: Attaching to current thread using JNI Version 1.2 (%d)\n",vmConnectionStatus); + JavaVMAttachArgs attachmentArgs; + attachmentArgs.version = JNI_VERSION_1_2; + attachmentArgs.name = NULL; + attachmentArgs.group = NULL; + attachReturnStatus = jvm->AttachCurrentThread((void **)&env, &attachmentArgs); + if ((env != NULL) && env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + } else { + // should really look for JNI_OK versus an error because it could have been JNI_EVERSION + // started method with thread hooked to VM so no need to attach again + //printf("Unhook: No need to attach because already attached %d\n",vmConnectionStatus); + } + + // we should always have an env by this point but lets be paranoid and check + if (env != NULL){ + env->DeleteGlobalRef(javaSinkObj); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + } + if (MethNum) { + delete [] MethName; + delete [] MethID; + } + // detach from thread only if we attached to it in this function + if (attachReturnStatus == 0){ + jvm->DetachCurrentThread(); + //printf("Unhook: Detached\n"); + } else { + //printf("Unhook: No need to detatch because attached prior to method\n"); + } + //fflush(stdout); +} + +// I only support the eventIID interface which was passed in +// by the DispatchEvent wrapper who looked it up as the +// source object's default source interface +STDMETHODIMP CallbackProxy::QueryInterface(REFIID rid, void **ppv) +{ + if (rid == IID_IUnknown || rid == IID_IDispatch) + { + *ppv = this; + AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP CallbackProxy::GetIDsOfNames(REFIID riid, + OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID) +{ + HRESULT result = S_OK; + for (UINT n = 0; n < cNames; n++) { + rgDispID[n] = DISPID_UNKNOWN; + USES_CONVERSION; + const char *current = W2A((OLECHAR *)rgszNames[n]); + // map name to dispID + for (int i = 0; iAttachCurrentThread((void **)&env, &attachmentArgs); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + + if (!eventMethodName) + { + // could not find this signature in list + // printf("Invoke: didn't find method name for dispatch id %d\n",dispID); + // this probably leaves a native thread attached to the vm when we don't want it + ThrowComFail(env, "Event method received was not defined as part of callback interface", -1); + + // should we detatch before returning?? We probably never get here if we ThrowComFail() + // jvm->DetachCurrentThread(); + return S_OK; + } + + // find the class of the InvocationHandler + jclass javaSinkClass = env->GetObjectClass(javaSinkObj); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + //printf("Invoke: Got sink class\n"); + jmethodID invokeMethod; + invokeMethod = env->GetMethodID(javaSinkClass, "invoke", "(Ljava/lang/String;[Lcom/jacob/com/Variant;)Lcom/jacob/com/Variant;"); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + jstring eventMethodNameAsString = env->NewStringUTF(eventMethodName); + //printf("Invoke: Got method name\n"); + // now do what we need for the variant + jmethodID getVariantMethod = env->GetMethodID(javaSinkClass, "getVariant", "()Lcom/jacob/com/Variant;"); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + //printf("Invoke: Found way too getVariant\n"); + jobject aVariantObj = env->CallObjectMethod(javaSinkObj, getVariantMethod); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + //printf("Invoke: Made Variant\n"); + jclass variantClass = env->GetObjectClass(aVariantObj); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + + // create the variant parameter array + // how many params + int numVariantParams = pDispParams->cArgs; + // make an array of them + jobjectArray varr = env->NewObjectArray(numVariantParams, variantClass, 0); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + //printf("Invoke: Created Array\n"); + int i,j; + for(i=numVariantParams-1,j=0;i>=0;i--,j++) + { + // construct a java variant holder + jobject arg = env->CallObjectMethod(javaSinkObj, getVariantMethod); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + // get the empty variant from it + VARIANT *va = extractVariant(env, arg); + // copy the value + VariantCopy(va, &pDispParams->rgvarg[i]); + // put it in the array + env->SetObjectArrayElement(varr, j, arg); + env->DeleteLocalRef(arg); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + } + //printf("Invoke: Filled Array\n"); + // Set up the return value + jobject ret; + + ret = env->CallObjectMethod(javaSinkObj, invokeMethod, + eventMethodNameAsString, varr); + //printf("Invoke: Invoked callback\n"); + if (!env->ExceptionOccurred() && ret != NULL) { + VariantCopy(pVarResult, extractVariant(env,ret)); + } + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + // don't need the first variant we created to get the class + // SF 1689061 change not accepted but put in as comment for later reminder + //Java_com_jacob_com_Variant_release(env, aVariantObj); + env->DeleteLocalRef(aVariantObj); + if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear();} + + // Begin code from Jiffie team that copies parameters back from java to COM + for(i=numVariantParams-1,j=0;i>=0;i--,j++) + { + jobject arg = env->GetObjectArrayElement(varr, j); + VARIANT *java = extractVariant(env, arg); + VARIANT *com = &pDispParams->rgvarg[i]; + convertJavaVariant(java, com); + // SF 1689061 change not accepted but put in as comment for later reminder + // note that a related fix has been submitted in SF 3435567 to do this in zeroVariant() method + //Java_com_jacob_com_Variant_release(env, arg); + zeroVariant(env, arg); + env->DeleteLocalRef(arg); + } + // End code from Jiffie team that copies parameters back from java to COM + // detach from thread + //printf("Invoke: Detatching\n"); + jvm->DetachCurrentThread(); + //fflush(stdout); + return S_OK; + } + return E_NOINTERFACE; +} + +void CallbackProxy::convertJavaVariant(VARIANT *java, VARIANT *com) { + + switch (com->vt) + { + case VT_DISPATCH: + { + switch (java->vt) + { + case VT_DISPATCH: + { + V_DISPATCH(com) = V_DISPATCH(java); + break; + } + + case VT_DISPATCH | VT_BYREF: + { + V_DISPATCH(com) = *V_DISPATCHREF(java); + break; + } + } + break; + } + + case VT_DISPATCH | VT_BYREF: + { + switch (java->vt) + { + case VT_DISPATCH: + { + *V_DISPATCHREF(com) = V_DISPATCH(java); + break; + } + + case VT_DISPATCH | VT_BYREF: + { + *V_DISPATCHREF(com) = *V_DISPATCHREF(java); + break; + } + } + break; + } + + case VT_BOOL: + { + switch (java->vt) + { + case VT_BOOL: + { + V_BOOL(com) = V_BOOL(java); + break; + } + + case VT_BOOL | VT_BYREF: + { + V_BOOL(com) = *V_BOOLREF(java); + break; + } + } + break; + } + + case VT_BOOL | VT_BYREF: + { + switch (java->vt) + { + case VT_BOOL: + { + *V_BOOLREF(com) = V_BOOL(java); + break; + } + + case VT_BOOL | VT_BYREF: + { + *V_BOOLREF(com) = *V_BOOLREF(java); + break; + } + } + break; + } + + case VT_UI1: + { + switch (java->vt) + { + case VT_UI1: + { + V_UI1(com) = V_UI1(java); + break; + } + + case VT_UI1 | VT_BYREF: + { + V_UI1(com) = *V_UI1REF(java); + break; + } + } + break; + } + + case VT_UI1 | VT_BYREF: + { + switch (java->vt) + { + case VT_UI1: + { + *V_UI1REF(com) = V_UI1(java); + break; + } + + case VT_UI1 | VT_BYREF: + { + *V_UI1REF(com) = *V_UI1REF(java); + break; + } + } + break; + } + + + case VT_I2: + { + switch (java->vt) + { + case VT_I2: + { + V_I2(com) = V_I2(java); + break; + } + + case VT_I2 | VT_BYREF: + { + V_I2(com) = *V_I2REF(java); + break; + } + } + break; + } + + case VT_I2 | VT_BYREF: + { + switch (java->vt) + { + case VT_I2: + { + *V_I2REF(com) = V_I2(java); + break; + } + + case VT_I2 | VT_BYREF: + { + *V_I2REF(com) = *V_I2REF(java); + break; + } + } + break; + } + + case VT_I4: + { + switch (java->vt) + { + case VT_I4: + { + V_I4(com) = V_I4(java); + break; + } + + case VT_I4 | VT_BYREF: + { + V_I4(com) = *V_I4REF(java); + break; + } + } + break; + } + + case VT_I4 | VT_BYREF: + { + switch (java->vt) + { + case VT_I4: + { + *V_I4REF(com) = V_I4(java); + break; + } + + case VT_I4 | VT_BYREF: + { + *V_I4REF(com) = *V_I4REF(java); + break; + } + } + break; + } + + case VT_R4: + { + switch (java->vt) + { + case VT_R4: + { + V_R4(com) = V_R4(java); + break; + } + + case VT_R4 | VT_BYREF: + { + V_R4(com) = *V_R4REF(java); + break; + } + } + break; + } + + case VT_R4 | VT_BYREF: + { + switch (java->vt) + { + case VT_R4: + { + *V_R4REF(com) = V_R4(java); + break; + } + + case VT_R4 | VT_BYREF: + { + *V_R4REF(com) = *V_R4REF(java); + break; + } + } + break; + } + + case VT_R8: + { + switch (java->vt) + { + case VT_R8: + { + V_R8(com) = V_R8(java); + break; + } + + case VT_R8 | VT_BYREF: + { + V_R8(com) = *V_R8REF(java); + break; + } + } + break; + } + + case VT_R8 | VT_BYREF: + { + switch (java->vt) + { + case VT_R8: + { + *V_R8REF(com) = V_R8(java); + break; + } + + case VT_R8 | VT_BYREF: + { + *V_R8REF(com) = *V_R8REF(java); + break; + } + } + break; + } + + case VT_I1: + { + switch (java->vt) + { + case VT_I1: + { + V_I1(com) = V_I1(java); + break; + } + + case VT_I1 | VT_BYREF: + { + V_I1(com) = *V_I1REF(java); + break; + } + } + break; + } + + case VT_I1 | VT_BYREF: + { + switch (java->vt) + { + case VT_I1: + { + *V_I1REF(com) = V_I1(java); + break; + } + + case VT_I1 | VT_BYREF: + { + *V_I1REF(com) = *V_I1REF(java); + break; + } + } + break; + } + + case VT_UI2: + { + switch (java->vt) + { + case VT_UI2: + { + V_UI2(com) = V_UI2(java); + break; + } + + case VT_UI2 | VT_BYREF: + { + V_UI2(com) = *V_UI2REF(java); + break; + } + } + break; + } + + case VT_UI2 | VT_BYREF: + { + switch (java->vt) + { + case VT_UI2: + { + *V_UI2REF(com) = V_UI2(java); + break; + } + + case VT_UI2 | VT_BYREF: + { + *V_UI2REF(com) = *V_UI2REF(java); + break; + } + } + break; + } + + case VT_UI4: + { + switch (java->vt) + { + case VT_UI4: + { + V_UI4(com) = V_UI4(java); + break; + } + + case VT_UI4 | VT_BYREF: + { + V_UI4(com) = *V_UI4REF(java); + break; + } + } + break; + } + + case VT_UI4 | VT_BYREF: + { + switch (java->vt) + { + case VT_UI4: + { + *V_UI4REF(com) = V_UI4(java); + break; + } + + case VT_UI4 | VT_BYREF: + { + *V_UI4REF(com) = *V_UI4REF(java); + break; + } + } + break; + } + + case VT_INT: + { + switch (java->vt) + { + case VT_INT: + { + V_INT(com) = V_INT(java); + break; + } + + case VT_INT | VT_BYREF: + { + V_INT(com) = *V_INTREF(java); + break; + } + } + break; + } + + case VT_INT | VT_BYREF: + { + switch (java->vt) + { + case VT_INT: + { + *V_INTREF(com) = V_INT(java); + break; + } + + case VT_INT | VT_BYREF: + { + *V_INTREF(com) = *V_INTREF(java); + break; + } + } + break; + } + + case VT_UINT: + { + switch (java->vt) + { + case VT_UINT: + { + V_UINT(com) = V_UINT(java); + break; + } + + case VT_UINT | VT_BYREF: + { + V_UINT(com) = *V_UINTREF(java); + break; + } + } + break; + } + + case VT_UINT | VT_BYREF: + { + switch (java->vt) + { + case VT_UINT: + { + *V_UINTREF(com) = V_UINT(java); + break; + } + + case VT_UINT | VT_BYREF: + { + *V_UINTREF(com) = *V_UINTREF(java); + break; + } + } + break; + } + + case VT_CY: + { + switch (java->vt) + { + case VT_CY: + { + V_CY(com) = V_CY(java); + break; + } + + case VT_CY | VT_BYREF: + { + V_CY(com) = *V_CYREF(java); + break; + } + } + break; + } + + case VT_CY | VT_BYREF: + { + switch (java->vt) + { + case VT_CY: + { + *V_CYREF(com) = V_CY(java); + break; + } + + case VT_CY | VT_BYREF: + { + *V_CYREF(com) = *V_CYREF(java); + break; + } + } + break; + } + + case VT_DATE: + { + switch (java->vt) + { + case VT_DATE: + { + V_DATE(com) = V_DATE(java); + break; + } + + case VT_DATE | VT_BYREF: + { + V_DATE(com) = *V_DATEREF(java); + break; + } + } + break; + } + + case VT_DATE | VT_BYREF: + { + switch (java->vt) + { + case VT_DATE: + { + *V_DATEREF(com) = V_DATE(java); + break; + } + + case VT_DATE | VT_BYREF: + { + *V_DATEREF(com) = *V_DATEREF(java); + break; + } + } + break; + } + + case VT_BSTR: + { + switch (java->vt) + { + case VT_BSTR: + { + V_BSTR(com) = V_BSTR(java); + break; + } + + case VT_BSTR | VT_BYREF: + { + V_BSTR(com) = *V_BSTRREF(java); + break; + } + } + break; + } + + case VT_BSTR | VT_BYREF: + { + switch (java->vt) + { + case VT_BSTR: + { + *V_BSTRREF(com) = V_BSTR(java); + break; + } + + case VT_BSTR | VT_BYREF: + { + *V_BSTRREF(com) = *V_BSTRREF(java); + break; + } + } + break; + } + + case VT_DECIMAL: + { + switch (java->vt) + { + case VT_DECIMAL: + { + V_DECIMAL(com) = V_DECIMAL(java); + break; + } + + case VT_DECIMAL | VT_BYREF: + { + V_DECIMAL(com) = *V_DECIMALREF(java); + break; + } + } + break; + } + + case VT_DECIMAL | VT_BYREF: + { + switch (java->vt) + { + case VT_DECIMAL: + { + *V_DECIMALREF(com) = V_DECIMAL(java); + break; + } + + case VT_DECIMAL | VT_BYREF: + { + *V_DECIMALREF(com) = *V_DECIMALREF(java); + break; + } + } + break; + } + + + } +} + + +STDMETHODIMP CallbackProxy::RegisterEvent(DISPID dispID, const char * methodName) +{ + int newMethNum = MethNum + 1; + DISPID* newMethID = new DISPID[newMethNum]; + const char **newMethName = new const char*[newMethNum]; + + if (0 != MethNum) { + memcpy(newMethID, MethID, MethNum * sizeof(DISPID)); + memcpy(newMethName, MethName, MethNum * sizeof(char*)); + delete [] MethID; + delete [] MethName; + MethID = NULL; + MethName = NULL; + } + + newMethID[MethNum] = dispID; + newMethName[MethNum] = methodName; + + MethID = newMethID; + MethName = newMethName; + MethNum = newMethNum; + + return S_OK; +} \ No newline at end of file diff --git a/jni/CallbackProxy.h b/jni/CallbackProxy.h new file mode 100644 index 0000000..da9a2f1 --- /dev/null +++ b/jni/CallbackProxy.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1999-2004 Sourceforge JACOB Project. + * All rights reserved. Originator: Dan Adler (http://danadler.com). + * Get more information about JACOB at http://sourceforge.net/projects/jacob-project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include "stdafx.h" +#include "util.h" + +/* + * An instance of this class stands between a connection point + * and a java object. When it gets invoked from the cp, it reflects + * the call into the java object dynamically. The eventIID is passed + * in as are the valid dispids and the corresponding names. A map + * is created between the dispids and the java object's method in + * the constructor. For now, all the java event methods have to have + * the same signature: (Variant[]) + */ +class CallbackProxy : public IDispatch +{ +private: + jobject javaSinkObj; // the java object to delegate calls + LONG m_cRef; // a reference counter + int MethNum; // number of methods in the callback interface + const char **MethName; // Array of method names + DISPID *MethID; // Array of method ids, used to match invokations to method names + JavaVM *jvm; // The java vm we are running + void convertJavaVariant(VARIANT *java, VARIANT *com); +public: + // constuct with a global JNI ref to a sink object + // to which we will delegate event callbacks + CallbackProxy(JNIEnv *jenv, + jobject aSinkObj); + ~CallbackProxy(); + + // IUnknown methods + STDMETHODIMP_(ULONG) AddRef(void) + { + LONG res = InterlockedIncrement(&m_cRef); + return res; + } + + STDMETHODIMP_(ULONG) Release(void) + { + LONG res = InterlockedDecrement(&m_cRef); + if (res == 0) { + delete this; + } + return res; + + } + + STDMETHODIMP QueryInterface(REFIID rid, void **ppv); + + // IDispatch methods + STDMETHODIMP GetTypeInfoCount(UINT *num) + { + *num = 0; + return S_OK; + } + + STDMETHODIMP GetTypeInfo(UINT, LCID, ITypeInfo **pptInfo) + { + *pptInfo=NULL; + return E_NOTIMPL; + } + + // These are the actual supported methods + STDMETHODIMP GetIDsOfNames(REFIID, OLECHAR **, UINT, LCID , DISPID *); + STDMETHODIMP Invoke(DISPID, REFIID, LCID, WORD , DISPPARAMS *, VARIANT *, EXCEPINFO *, UINT *); + STDMETHODIMP RegisterEvent(DISPID, const char *); +}; diff --git a/jni/DispatchCallback.cpp b/jni/DispatchCallback.cpp new file mode 100644 index 0000000..087bfa5 --- /dev/null +++ b/jni/DispatchCallback.cpp @@ -0,0 +1,118 @@ +/* +* Copyright (c) 1999-2004 Sourceforge JACOB Project. +* All rights reserved. Originator: Dan Adler (http://danadler.com). +* Get more information about JACOB at http://sourceforge.net/projects/jacob-project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "DispatchCallback.h" +#include "CallbackProxy.h" +// Win32 support for Ole Automation +#include +#include +#include +#include +#include +#include + +#include "util.h" + +extern "C" +{ + +#define PROXY_FLD "m_pConnPtProxy" + + // defined below + BOOL GetEventIID(IUnknown*, IID*, CComBSTR **, DISPID **, int *, LPOLESTR); + BOOL GetEventIIDForTypeLib(BSTR, IID*, CComBSTR **, DISPID **, int *, LPOLESTR); + BOOL getClassInfoFromProgId(LPOLESTR bsProgId, LPTYPEINFO *pClassInfo); + BOOL MapEventIIDs(IID*, CComBSTR **, DISPID **, int *, LPOLESTR, LPTYPEINFO); + + // extract a CallbackProxy* from a jobject + CallbackProxy *CallbackProxyExtractProxy(JNIEnv *env, jobject arg) + { + jclass argClass = env->GetObjectClass(arg); + jfieldID ajf = env->GetFieldID(argClass, PROXY_FLD, "J"); + jlong anum = env->GetLongField(arg, ajf); + CallbackProxy *v = (CallbackProxy *)anum; + return v; + } + + /* + * pushes the CallbackProxy (*cbp) into tje jobject in the PROXY_FLD location + */ + void CallbackProxyPutProxy(JNIEnv *env, jobject arg, CallbackProxy *cbp) + { + jclass argClass = env->GetObjectClass(arg); + jfieldID ajf = env->GetFieldID(argClass, PROXY_FLD, "J"); + jlong anum = env->GetLongField(arg, ajf); + env->SetLongField(arg, ajf, (jlong)cbp); + } + + + /* + * Class: com_jacob_com_DispatchCallback + * Method: init3 + * Signature: (Lcom/jacob/com/Dispatch;Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_init3 + (JNIEnv *env, jobject _this, jobject sink) + { + CallbackProxy *cbp = new CallbackProxy(env, sink); + // need to store ep on _this, in case it gets collected + CallbackProxyPutProxy(env, _this, cbp); + } + + /* + * Class: DispatchCallback + * Method: release + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_release + (JNIEnv *env, jobject _this) + { + CallbackProxy *ep = CallbackProxyExtractProxy(env, _this); + if (ep) { + ep->Release(); + CallbackProxyPutProxy(env, _this, NULL); + } + } + + /* + * Class: com_jacob_com_DispatchCallback + * Method: registerEvent + * Signature: (I;Ljava/lang/String;)V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_registerEvent + (JNIEnv *env, jobject _this, jint _id, jstring _methodeName) + { + if (NULL == _methodeName) { + ThrowComFail(env, "The mehtod name should not be null.", -1); + return; + } + + if (0 == _id) { + ThrowComFail(env, "The dispatch id should be 0.", -1); + return; + } + + CallbackProxy *ep = CallbackProxyExtractProxy(env, _this); + if (ep) { + DISPID dispId = _id; + const char *methodeName = env->GetStringUTFChars(_methodeName, NULL); + ep->RegisterEvent(dispId, methodeName); + } + } +} diff --git a/jni/DispatchCallback.h b/jni/DispatchCallback.h new file mode 100644 index 0000000..d872a63 --- /dev/null +++ b/jni/DispatchCallback.h @@ -0,0 +1,58 @@ +/* +* Copyright (c) 1999-2004 Sourceforge JACOB Project. +* All rights reserved. Originator: Dan Adler (http://danadler.com). +* Get more information about JACOB at http://sourceforge.net/projects/jacob-project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +/* Header for class DispatchCallback */ + +#ifndef _Included_DispatchCallback +#define _Included_DispatchCallback +#ifdef __cplusplus +extern "C" { +#endif + + /* + * Class: com_jacob_com_DispatchCallback + * Method: init3 + * Signature: (Ljava/lang/Object)V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_init3 + (JNIEnv *, jobject, jobject); + + /* + * Class: DispatchCallback + * Method: release + * Signature: ()V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_release + (JNIEnv *, jobject); + + /* + * Class: com_jacob_com_DispatchCallback + * Method: registerEvent + * Signature: (I;Ljava/lang/String;)V + */ + JNIEXPORT void JNICALL Java_com_jacob_com_DispatchCallback_registerEvent + (JNIEnv *, jobject, jint, jstring); + +#ifdef __cplusplus +} +#endif +#endif + + diff --git a/src/com/jacob/com/DispatchCallback.java b/src/com/jacob/com/DispatchCallback.java new file mode 100644 index 0000000..934fbd0 --- /dev/null +++ b/src/com/jacob/com/DispatchCallback.java @@ -0,0 +1,138 @@ +/* +* Copyright (c) 1999-2004 Sourceforge JACOB Project. +* All rights reserved. Originator: Dan Adler (http://danadler.com). +* Get more information about JACOB at http://sourceforge.net/projects/jacob-project +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +package com.jacob.com; + +/** + * + */ +public class DispatchCallback extends JacobObject { + + /** + * pointer to an MS data struct. The COM layer knows the name of this + * variable and puts the windows memory pointer here. + */ + long m_pConnPtProxy = 0; + + /** + * the wrapper for the event sink. This object is the one that will be sent + * a message when an event occurs in the MS layer. Normally, the + * InvocationProxy will forward the messages to a wrapped object that it + * contains. + */ + InvocationProxy mInvocationProxy = null; + + private Dispatch dispatch = null; + + public DispatchCallback(Object eventSink) { + if (JacobObject.isDebugEnabled()) { + System.out.println("DispatchCallback: Registering " + eventSink + + "for calbacks "); + } + + if (eventSink instanceof InvocationProxy) { + this.mInvocationProxy = (InvocationProxy) eventSink; + } else { + this.mInvocationProxy = this.getInvocationProxy(eventSink); + } + if (this.mInvocationProxy != null) { + this.init3(this.mInvocationProxy); + } else { + if (JacobObject.isDebugEnabled()) { + JacobObject.debug("Cannot register null event sink for events"); + } + throw new IllegalArgumentException( + "Cannot register null event sink for events"); + } + + this.dispatch = new Dispatch(this.m_pConnPtProxy) {}; + } + + /** + * Returns an instance of the proxy configured with pTargetObject as its + * target + * + * @param pTargetObject + * @return InvocationProxy an instance of the proxy this DispatchEvents will + * send to the COM layer + */ + protected InvocationProxy getInvocationProxy(Object pTargetObject) { + final InvocationProxy newProxy = new InvocationProxyAllVariants(); + newProxy.setTarget(pTargetObject); + return newProxy; + } + + /** + * hooks up a connection point proxy by progId event methods on the sink + * object will be called by name with a signature of (Variant[] args) + * + * You must specify the location of the typeLib. + * + * @param sink + * the object that will receive the messages + */ + private native void init3(Object sink); + + /** + * now private so only this object can asccess was: call this to explicitly + * release the com object before gc + * + */ + private native void release(); + + protected native void registerEvent(int eventCode, String methodName); + + /* + * (non-Javadoc) + * + * @see java.lang.Object#finalize() + */ + @Override + protected void finalize() { + this.safeRelease(); + } + + /* + * (non-Javadoc) + * + * @see com.jacob.com.JacobObject#safeRelease() + */ + @Override + public void safeRelease() { + if (this.mInvocationProxy != null) { + this.mInvocationProxy.setTarget(null); + } + this.mInvocationProxy = null; + super.safeRelease(); + if (this.m_pConnPtProxy != 0) { + this.release(); + this.m_pConnPtProxy = 0; + } else { + // looks like a double release + if (isDebugEnabled()) { + debug("DispatchEvents:" + this.hashCode() + " double release"); + } + } + this.dispatch = null; + } + + protected Dispatch dispatch() { + return this.dispatch; + } +}