Re: status of nio version

Roger I Martin PhD <[email protected]> Thu, 2 Jun 2005 20:12:03 -0400
Newsgroups gmane.comp.windows.devel.jawin
Message-ID <[email protected]>
Thanks Robert,

Just got home.

Interesting and more to think about.  1.5 didn't fix anything concerning
ByteBuffers?  Anybody familiar with the channels?  Without know how they
work I do have a case where reading in a 290 MB file it really works:-)
But there is memory files which I was thinking could be employed for
huge data situations.  Determining when is the problem.

Robert Hastings wrote:

>When I think of [out] parameters I think of two cases.
>
>1) The [out] parameter is a primitive type. COM requires that the type of
>the [out] parameter is a pointer to the primitive type so that it can use
>the pointer to change the value.
>
>2) The [out] parameter is a pointer to a pointer type. The passed pointer
>points to a memory area that will be over-written with a pointer value that
>points to the [out] value. Stay that ten times.
>
>Thinking in terms of byte buffers the first case it pretty workable for
>direct byte buffers, but those will each use a page of memory (4K). With
>direct byte buffers you could get pointer to the memory used on the JNI side
>and pass that as the [out] param. When the primitive value is written into
>the bytes they will show up on the java side and you could use on of the
>many get methods.
>
>For the pointer case, you'd end up with a byte buffer that contains a
>pointer to native memory. I suppose you could write a JNI call that will
>wrap those bytes with a byte buffer and then you'd have access. You have to
>free those bytes with the correct native call. That is if you have a BSTR
>you have to use SysFreeString, if you have a SAFEARRAY, you have to use
>SafeArrayDestroy, if you have a VARIANT you need VariantClear, and all other
>cases should map down to CoTaskMemFree (unless I forgot a case :-).
>
>To address the direct byte buffer 4K problem you might setup some JNI code
>that will use malloc/free to create smaller byte buffers. JNI allows you to
>create a byte buffer to wrap a smaller memory area. I don't know why this
>feature is only available on the JNI side.
>
>Robert
>
>-----Original Message-----
>From: Discussion of Java/Win32/COM integration with Jawin
>[mailto:[email protected]] On Behalf Of Roger I Martin PhD
>Sent: Thursday, June 02, 2005 3:31 PM
>To: [email protected]
>Subject: Re: [JAWIN] status of nio version
>
>Thanks Morten,
>
>A more indept discussion will follow.
>
>Project organization I leave the howto in your hands:-)  Let me know
>what works for new development being cvs'ed.  Branch?
>
>I started an OleControl.cpp so I could work without damaging
>GenericStub.cpp but have no plans for pushing it into cvs that way.  As
>I went I kept using less and less of the original linear stream
>transforms and testing.  For the valid issues you raise about complex
>types, am looking at filling the ByteBuffer with the Variant structure
>at the beginning and the rest of it with the data in direct and native
>byte order.  Then make a pre invoke call to the native to set the
>pointers in place.  This may be problematic if memory changes but is
>there a way to protect from this?
>
>You mention [OUT] parameters in the return and I must display my true
>ignorance of the linear byte cpp marshaling:-)  I never understood  it
>and never applied it using all of the return capability:-)  Did JNI code
>generation instead:-) Originally I wanted to get the stub generator
>working in Java with native type info support and xml technology.  Then
>Josh Passenger built the TypeLib Browser and [whisper] we both wanted
>some of the original marshallers to return with enthusiasm.  Currently
>what I'm trying to do is return everything back thru their place in the
>arg list or ByteBuffer array.  Maybe I'm changing it too radically.
>
>I can tell you that for the prior marshalling I can only tinker with
>fixes but don't understand the native marshaling code.  I never saw
>anything constructed by the COM side appear on the Java side.  Or if a
>string changed dimension I never got it. Maybe we didn't finish this
>part of new stubbing for the returns?
>
>Quickly,  the member id FUNCDEC.memid is used by IDispatch and the
>FUNCDESC.oVft is the vtable offset which will figure in coclasses (I did
>not have the tlb retrieval supply memid before).  In a small test
>FUNCDESC.oVft is zero if it is not a virtual function and vice versa for
>the FUNCDEC.memid.  We can make the GetIDofName
>orIDispatch.getIDsofNames functional for those who do not have hard info
>on the memid and choose not to use the stub generation?  By this it can
>be retrieved during run time by the function name as usual.
>int id[1];
>String names[1];
>names[0]=functionName;
>getIDsofNames(...names...id
>invoke(id[0],....);
>
>every time or they can get all the ones they want during initialization
>and use as needed and without repeated calls to getIDsofNames.
>
>More later,
>
>Roger
>
>
>Morten Andersen wrote:
>
>
>
>>Hi Roger,
>>
>>Impressive thoughts you seem to have put into this. I have added a
>>couple of comments, here and there below (I have far from comments or
>>ideas on everything, as there are lots I don't know much about)
>>
>>Roger I Martin PhD wrote:
>>
>>
>>
>>>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.
>>>
>>>
>>>
>>That is of course the safe option. But I fear the risk of bit-root,
>>where we suddenly have two different ways to do the same thing, and then
>>there will be a risk that one of them doesn't get appropriate attention
>>and will degrade over time. I assume I am more to a "hard-cut" switch,
>>although I am aware that this may burn some bridges to existing
>>developers.
>>
>>But that is solely up to you.
>>
>>
>>
>>>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 details of the IdentityManager is not entirely fresh in my memory.
>>But if it is possible to work on the interface only, that is of course
>>preferable. But will it be possible without exposing the internal Jawin
>>reference counting for GIT-cookie and/or vtable pointer information.
>>
>>But again this is far away in my memory, so I assume if you have a fresh
>>overview of the internal working of IdentityManager, you have considered
>>pro and cons.
>>
>>[SNIP]
>>
>>
>>
>>
>>>3)  Everything I am doing is aimed at speed and seamless bridging.
>>>
>>>
>>With respect to the speed, a couple of the unittests are actually some
>>indicate perfomance tests. That is the classes in test/org/jawin/perf,
>>which can be run with "ant test", after this you can inspect the run
>>time for these in JUnit-report. I assume you should probably dublicate
>>these tests for the new NIO-interface and se what speed gain we can
>>expect (we could set up a betting pool in advance :-)).
>>
>>
>>
>>>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.
>>>
>>>
>>That depends a little bit on what direction we want the project to take.
>>If I understand you correctly this will disable the option to do
>>"type-un-safe" VB-script coding style
>>(http://jawinproject.sourceforge.net/jawin.html#callingScript ) and
>>force developers to generate and use stubs?
>>
>>I am not that strong on COM-terms, but is it correctly understood that
>>what you suggest is that all stubs should be VTable based, and that we
>>won't really use and/or expose the functionality offered by the
>>IDispatch interface (or is this just me mixing up terms?).
>>
>>When discussing if this is direction we want to take, we should probably
>>also discuss what support we want for calling old style (non-COM) DLL
>>entry points. Is this something we want to keep supporting, or should we
>>give up on that part, and refer people to more mature projects for such
>>functionality (most of the under-documented marshalling instructions are
>>actually for this). Or this something we should direct attention to?
>>
>>[SNIP]
>>
>>
>>
>>>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.
>>>
>>>
>>>
>>But the "javaOut" byte-array contains both [RETVAL] and [OUT]
>>parameters. Will a "random" mix of [RETVAL] and [OUT] parameters still
>>be supported with this change?
>>
>>
>>
>>>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(ar
>gArray,
>
>
>>>(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(ar
>gArray,
>
>
>>>(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;
>>>}
>>>
>>>
>>This looks very exciting. So I am understanding it correctly if what you
>>want to change the marshalling to is a scheme like:
>>  "the-java-side-marshall-directly-into-the-native-format"
>>which can be pushed directly into the "Invoke" method.
>>
>>I am not that deep into native Variant types, but is it also possible to
>>allocate the Variant-memory for the types with special
>>allocation/deallocation methods (I assume this is SafeArray and BSTR and
>>perhaps other?), or are this just helper methods MS added to make it
>>easier to remember memory-allocation/deallocation for these more complex
>>types.
>>
>>If you want some "weird-type" methods to test on, I think we have some
>>for e.g. SafeArrays in SafeArrays in the test class
>>test/org/jawin/DispatchTestBase.
>>
>>Best Regards
>>Morten
>>
>>
>>
>
>
>