status of nio version
Roger I Martin PhD <[email protected]> Wed, 1 Jun 2005 10:00:55 -0400
| Newsgroups | gmane.comp.windows.devel.jawin |
|---|---|
| Message-ID | <[email protected]> |
There are a number of issues which I would like to know if the changes
adversely affect anyone.
0) All current marshalling functionality remains available while new
functionality is added.
1) Is it a problem for anyone if the IdentityManager uses the IUnknown
interface to work with the Jawin classes that implement it instead of
the COMPtr directly? The COMPtr can still be instantiated by the
IdentityManager but requires a cast when returned or used in arguments.
The reason for the change is to allow other implementations to be
obtained via the IUnknown interface rather than only extending COMPtr
which at this time does not permit the object to extend anything else.
For example a new visual component OLEControl extends
javax.swing.JWindow and implements IUnknown, IOleControl, IDispatch, etc.
2) The Jawin Type Browser employs the Saxon XSLT transformer and
upgrades the code generating stylesheets to XSLT 2.0 and XPath 2.0
capability. Very little Type Browser code changes. We will include the
saxon jars and license in the downloads and next releases and remove Xalan.
3) Everything I am doing is aimed at speed and seamless bridging. The
member id from the function description will be used instead of passing
a String with the function name to the new nio native calls and then
converting to a BSTR and calling the method to get the member id to
pass to the IDispatch invoke. The Jawin Type Browser is updated to
provide the xml output with the member id. The vtableoffset will be
used for virtual function events and callbacks. Is there any reason
relying on the member id from the tlb's would be problematic? I am
imitating what I see when a OleControl is dropped into a Visual C++ project.
This eliminates
CComBSTR meth;
meth.Attach(JNIComUtil::jstobs(env, jmeth));
DISPID dwDispID;
HRESULT hr = disp.GetIDOfName(meth, &dwDispID);
if (SUCCEEDED(hr)) {
from every call.
4) Creating a OleControlStub for all the new marshalling and leaving
the GenericStub as is.
5) Am providing an invoke method for every type of return( similar to
the way JNI is organized). The stylesheets will pick the right one when
generating code.
invokeVoidMethod
invokeIntMethod
...
invokeObjectMethod
These eliminate the need for
return MarshalAllocator::allocateByteArray(env,
javaOut.getMem(), javaOut.getPos());
and replaces this with the direct application of the return Variant such as
return retVar.lVal;
for integer returning methods.
6) The argument list for every Jawin native invocation call is being
reduced to jint dwDispID, jobjectArray argArray, jint peer, jint unknown.
dwDispID = member ID
argArray = array of java.nio.ByteBuffer's. One for each argument and
each contains a direct memory access to Variant.
example:
JNIEXPORT jint JNICALL Java_org_jawin_marshal_OleControlStub_invokeIntMethod
(JNIEnv* env, jobject obj, jint dwDispID, jobjectArray argArray, jint
peer, jint unknown)
Notice the instString is gone which eliminates
JNIComUtil::jstostr(env, instString, str);
IStreamOnMemory instructions(str.c_str(), str.length() + 1);
...
Transform tin(env, &br, javaIn, instructions, comIn, NULL);
...
//write retval into stream
Transform tret(env, &br, result, instructions, javaOut, NULL);
//write out params into stream
Transform tout(env, &br, comOut, instructions, javaOut, NULL);
The direct access to the ByteBuffer variants eliminates
IStreamOnMemory javaIn(request, requestSize, env);
jint stackSizeWithRet = stackSize + 1;
// Allocate memory for variants
size_t vntsSize = sizeof(VARIANT) * stackSizeWithRet;
VARIANT* vnts = (VARIANT*)MarshalAllocator::SafeMalloc(vntsSize,
NULL); // should we pass the BatchReleaser?
for (int i = 0; i < stackSizeWithRet; ++i) {
::VariantInit(vnts + i);
}
OStreamOnMemory comIn(vnts, vntsSize, true, true);
...
IStreamOnMemory result((byte*)comIn.getMem() +
stackSize*sizeof(VARIANT), sizeof(VARIANT));
IStreamOnMemory comOut((byte*)comIn.getMem(),
stackSize*sizeof(VARIANT));
with
int arrayLength=env->GetArrayLength(argArray);
VARIANTARG* pVar=new VARIANTARG[arrayLength];
for(int i=0;i<arrayLength;i++)
{
pVar[i]=((VARIANT*)env->GetDirectBufferAddress(env->GetObjectArrayElement(argArray,
(jint)i)))[0];
}
VARIANT retVar;
The marshalling code is simplified to
JNIEXPORT jint JNICALL Java_org_jawin_marshal_OleControlStub_invokeIntMethod
(JNIEnv* env, jobject obj, jint dwDispID, jobjectArray argArray, jint
peer, jint unknown)
{
long result;
se_translator translator;
try {
int arrayLength=env->GetArrayLength(argArray);
VARIANTARG* pVar=new VARIANTARG[arrayLength];
for(int i=0;i<arrayLength;i++)
{
pVar[i]=((VARIANT*)env->GetDirectBufferAddress(env->GetObjectArrayElement(argArray,
(jint)i)))[0];
}
VARIANT retVar;
CComPtr<IDispatch> cpUnk;
getUnknown(IID_IDispatch, peer, unknown, (IUnknown**) &cpUnk);
CComDispatchDriver disp(cpUnk);
IOleControl* olectl=NULL;
cpUnk->QueryInterface(IID_IOleControl, (void **)&olectl);
HRESULT hr;
DISPID dispidPut = DISPID_VALUE;//DISPATCH_METHOD;
DISPPARAMS dispparams;// = { pVar, NULL,
(int)stackSize+1, 0};
memset(&dispparams, 0, sizeof(dispparams));
dispparams.rgvarg=pVar;
//dispparams.rgdispidNamedArgs=&dispidPut;
dispparams.cArgs=arrayLength;
//dispparams.cNamedArgs=1;
EXCEPINFO excepInfo;
unsigned int argErr;
//IDispatch* idisp=(IDispatch*)disp;
hr = ((IDispatch*)olectl)->Invoke(dwDispID, IID_NULL,
LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &retVar, &excepInfo,
&argErr);
//hr = disp.InvokeN((int)dwDispID, pVar, arrayLength,
&retVar);
olectl->Release();
JNI_HR(hr);
return retVar.lVal;
}
HANDLE_WIN32_EXCEPTIONS()
HANDLE_JNI_EXCEPTIONS()
return 0;
}
Note: Still experimenting with which invoke to use. Having difficulty
with coclass, GUIDs, CLSIDs, catastrophic failures, etc.:-(
New functionality needs to be added when the COM constructs and arg or
changes it's dimension(s). But notice each arg can be handled
independently without the need to rearrange a sometimes huge linear byte
marshalling scheme around; expending and contracting for each changing
argument. Now for such any argument it will be possible to natively
construct a java.nio.ByteBuffer and fill it with an appropriate Variant
where the type is already known by the Java arg.
7) New put and get calls for the DISPATCH_PROPERTYGET and
DISPATCH_PROPERTYPUT types of invokes. Again similar to JNI there will
be multiple property invocations such as:
putInt
putDouble
...
putObject
...
getInt
getDouble
...
getObject
Again to eliminate decision making during runtime. All things that can
be decided from the type info during the Type Browser and stylesheet
phase will be used to eliminate runtime decisions and instructions.
8) On the Java side of Jawin a new set of xslt's are being developed to
create the interface layer. The interface layer will be larger and
specific but will no longer call the methods in the Variant class or use
the org.jawin.io stream classes(NakedByteStream,
LittleEndianInputStream, LittleEndianOutputStream) A typical interface
method will look like:
public int IntegerTest(int index) throws COMException
{
java.nio.ByteBuffer[] bba=new java.nio.ByteBuffer[1];
java.nio.ByteBuffer bb=java.nio.ByteBuffer.allocateDirect(16);
bb.order(java.nio.ByteOrder.nativeOrder());
bba[0]=bb.putShort((short)VarTypes.VT_I4).putShort((short)0).putShort((short)0).putShort((short)0).putInt(index);
return invokeIntMethod((int)0x01, bba);
}
9) The JAWT functionality allows a visible Ole Control window to be
painted onto the surface of a java.awt.Canvas in a javax.swing.JWindow.
createControl and paint methods are being added to implement visible
painting.
10) still testing how to get a generic C++ callback function to employ
for every virtual function in the vtable. When we have it, from it we
can call the coclasses Java interface methods where the user can write
their Java implementation. Any howto information on this part would be
greatly appreciated.
Any thoughts, ideas, foreseeable troubles with the refactoring and
applying nio are appreciated.
-Roger