Re: Unable to get meaningful error info from VB dll

Claude Eisenhut <[email protected]> Thu, 8 Jun 2006 11:53:51 +0200
Newsgroups gmane.comp.windows.devel.jawin
Message-ID <014001c68ae1$7b9f4cf0$1e00000a@lemon>
I have the same problem and investigated it a little bit.

I think the problem is in the C++ part near the GetErrorInfo() call.
According to the MS doc, befor you can call GetErrorInfo, you have to call
pObjectWithError->QueryInterface(IID_ISupportErrorInfo,...)
and
InterfaceSupportsErrorInfo(...)

see "Retrieving Error Information (Component Automation) "
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/automat/htm
l/0bd640a4-e93f-4201-8789-61ba7178ce15.asp

And also
// Do not test the return of GetErrorInfo. It can succeed and return
// a NULL pointer in pIErrorInfoAll. Simply test the pointer.
At http://msdn2.microsoft.com/en-us/library/ms131391.aspx

So far, I didn't have time to try this.

Claude

----- Original Message -----
From: "Brian Hirsch" <[email protected]>
To: <[email protected]>
Sent: Wednesday, June 07, 2006 11:54 PM
Subject: [JAWIN] FOLLOWUP: Re: [JAWIN] Unable to get meaningful error info
from VB dll


> First, thanks Sean for responding.  I appreciate the ideas to try.  We are
still having the same problem, however.
>
>   Taking a slightly different approach, is there anyone who has a working
example of a simple VB class causing an error and you receive good
information back?  If we had that, perhaps we could work from there.
>
>   Also, if anyone has ideas on what we could try or what we're missing, it
would be greatly appreciated.
>
>   Thanks
>   Brian
>
> Brian Hirsch <[email protected]> wrote:
>   Changing the method to the following make no difference.
> Public Function DivisionByZeroError() As Long
> DivisionByZeroError = 1 / 0
> End Function
> I have tried Err.Raise and that also make no difference. This is a very
simple test for the purpose of asking the question - the result is the same
for all VB dlls.
> Have also tried using the setErrorInfo and GetErrorInfo methods - result
is the same.
> I have tried wrapping a C++ DLL and without any additional work the error
is correctly reported, similar to the case for ADODB.
> I have stepped through the code and the difference between the C++ result
and the VB result occurs inside the call to the Native method
dispatchInvoke0. When the error information is passed up correctly the call
to the COMException constructor differ as follow:
>
> In the working case (C++ and example shown ADODB) the
dispatchInvoke0method calls the following constructor for COMException. As
shown this calls back into the verbose Exception constructor as COMException
extends Exception
> public COMException(int hresult, String desc, String source, String guid)
{
> super (desc + "[src=" + source + ",guid=" + guid+ "]");
> this.hresult = hresult; }
>
> However, in the failure case (VB) the dispatchInvoke0 method calls to a
different constructor for COMException. This calls into a more limited
constructor on Exception.
> public COMException(int hresult, String text) {
> super(text);
> this.hresult = hresult; }
> The problem I have is that I do not know what happens inside
dispatchInvoke0 that causes different constructors to be called.
> For anyone familiar with C++, the method in question is
> /**
> * java marshalling/unmarshalling, before/after the invocation of a native
dispatch based COM method
> */
> JNIEXPORT jbyteArray JNICALL
Java_org_jawin_marshal_GenericStub_dispatchInvoke0
> (JNIEnv* env, jclass, jstring instString, jint stackSize, jint
requestSize, jbyteArray request,
> jstring jmeth, int flags, jint peer, jint unknown)
> {
> se_translator translator;
> try {
> string str;
> JNIComUtil::jstostr(env, instString, str);
> IStreamOnMemory instructions(str.c_str(), str.length() + 1);
> CComBSTR meth;
> meth.Attach(JNIComUtil::jstobs(env, jmeth));
> BatchReleaser br;
>
> 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);
> Transform tin(env, &br, javaIn, instructions, comIn, NULL);
> callDisp(meth, stackSize, flags, peer, unknown, (void*) comIn.getMem());
>
> IStreamOnMemory result((byte*)comIn.getMem() + stackSize*sizeof(VARIANT),
sizeof(VARIANT));
> IStreamOnMemory comOut((byte*)comIn.getMem(), stackSize*sizeof(VARIANT));
> OStreamOnMemory javaOut(calloc(sizeof(VARIANT), 1), sizeof(VARIANT), true,
true);
> //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);
>
> // call the batch releaser explicit since we would otherwise be unable to
call
> // VariantClear below on SafeArrays, as they would be locked ->
VariantClear would
> // return DISP_E_ARRAYISLOCKED and we would leak.
> br.~BatchReleaser();
>
> // If return type is neither IDispatch nor IUnknown, then
> // free the Variant to avoid a memory leak. In the case of
> // IDispatch or IUnknown, the object would be released causing
> // Java to have a reference to a freed object
>
> // FIXME - what are the "memory ownership"-rules for IDispatch
> // what should we do with any [out] VARIANTS? - from the performance
tests, it
> // doesn't look like we are leaking.
> VARIANT* tmp = vnts + stackSize;
> if ((tmp->vt != VT_DISPATCH) && (tmp->vt != VT_UNKNOWN)) {
> ::VariantClear(tmp); // pt. we ignores any fails here - as we can't really
do anything but leak?
> }
>
> if (javaOut.getPos() == 0) {
> return 0;
> }
> return MarshalAllocator::allocateByteArray(env, javaOut.getMem(),
javaOut.getPos());
> }
> HANDLE_WIN32_EXCEPTIONS()
> HANDLE_JNI_EXCEPTIONS()
> return 0;
> }
>
>
>
> "Mcnamara, Sean D" wrote: Brian,
>
> Perhaps the line
>
> CreateObject("DebugTools_80.Helper").LogAndReRaiseVBError Err, App, Erl,
sThisProject, sThisComponent, sThisFunction
>
> is incorrectly using the Err object? I've never worked with a
DebugTools_80.Helper object, but you need to use the Err.Raise method with
the correct parameters, including the number:
>
> Dim desiredNum As Integer
> Err.Raise number:=vbObjectError + desiredNum, etc1, etc2, etc3, etc4
>
> Also, make sure your VB DLL is not compiled with options to eliminate
div/0 checks! Otherwise the VBVM60.DLL will, itself, divide by zero and
cause your module to crash.
>
> Is your LogAndReRaiseVBError function "logging" this error anywhere? Try
and verify that this line of code is actually being executed. For instance,
try displaying a MsgBox before you call this statement, to make sure that
your error handler is executed. JAWIN should have no problem displaying
message boxes without modifying your code, if I recall correctly...
>
>
>
>
> -----Original Message-----
> From: Discussion of Java/Win32/COM integration with Jawin
[mailto:[email protected]] On Behalf Of Brian Hirsch
> Sent: Thursday, June 01, 2006 8:25 AM
> To: [email protected]
> Subject: [JAWIN] Unable to get meaningful error info from VB dll
>
> We've been unable to get meaningful error information back from a method
call to a VB dll. My configuration is Windows XP, Java 1.4, Jawin 2.0,
Visual Studio SP 6. We've created a simple VB class with one method:
DivisionByZeroError. As you'd guess, this method tries to divide by zero.
I've included all the source code at the bottom. Wrapper classes have been
created for the VB class and are used to access the VB class.
> When we call the method, it is executing the code and is coming back with
an COMException, but all the detailed message says is: Exception occurred.
Here's the output from the calling java class:
> The return was error Info :-2147024809
> org.jawin.COMException: 80020009: Exception occurred.
> at org.jawin.marshal.GenericStub.dispatchInvoke0(Native Method)
> at org.jawin.marshal.GenericStub.dispatchInvoke(GenericStub.java:84)
> at org.jawin.DispatchPtr.invokeN(DispatchPtr.java:473)
> at org.jawin.DispatchPtr.invokeN(DispatchPtr.java:433)
> at com.cognos.baia.dtptest.DTP.DivisionByZeroError(DTP.java:18)
> at com.cognos.baia.ado.Test.main(Test.java:88)
>
> We get an hresult (-2147352567), but no good exception information.
> As another test, we set up wrappers to access an ADODB dll. When we try to
open a connection with an incorrect connection string, we get this in the
detailed message:
> [Microsoft][ODBC Driver Manager] Data source name not found and no default
driver specified[src=Microsoft OLE DB Provider for ODBC
Drivers,guid={0C733A8B-2A1C-11CE-ADE5-00AA0044773D}]
>
> Good stuff!
>
> the stack trace looks like this:
> org.jawin.COMException: 80020009: [Microsoft][ODBC Driver Manager] Data
source name not found and no default driver specified[src=Microsoft OLE DB
Provider for ODBC Drivers,guid={0C733A8B-2A1C-11CE-ADE5-00AA0044773D}]
> The return was error Info from Connection:-2147024809
> at org.jawin.marshal.GenericStub.dispatchInvoke0(Native Method)
> at org.jawin.marshal.GenericStub.dispatchInvoke(GenericStub.java:84)
> at org.jawin.DispatchPtr.invokeN(DispatchPtr.java:473)
> at org.jawin.DispatchPtr.invokeN(DispatchPtr.java:433)
> at org.jawin.DispatchPtr.invoke(DispatchPtr.java:377)
> at com.cognos.baia.ado.Connection.Open(Connection.java:85)
> at com.cognos.baia.ado.Test.getCommand(Test.java:48)
> at com.cognos.baia.ado.Test.main(Test.java:104)
>
> So, we get good error information from the ADODB call, but minimal from
the VB call. What are we doing wrong? Why can't we get better error
information back from this VB dll?
>
> Thanks
> Brian
>
> Here's the code from the VB class:
> Public Function DivisionByZeroError() As Long
> '
> On Error GoTo ErrorHandler
> Const sThisProject As String = "Project1": Const sThisComponent As String
= "DTP": Const sThisFunction As String = "DivisionByZeroError": Const
sThisProcedure As String = sThisProject & "." & sThisComponent & "." &
sThisFunction
> '
>
> 100 DivisionByZeroError = 1 / 0
>
>
> '
> Exit Function
> ErrorHandler:
> CreateObject("DebugTools_80.Helper").LogAndReRaiseVBError Err, App, Erl,
sThisProject, sThisComponent, sThisFunction
> '
> End Function
>
> Here's how we call it in Java:
> try {
> Ole32.CoInitialize();
> DTP dtp = new DTP();
> dtp.DivisionByZeroError();
> Ole32.CoUninitialize();
> } catch (COMException e) {
> // TODO Auto-generated catch block
> int errorInfo = getErrorInfo();
> System.out.println("The return was error Info :" + errorInfo);
> e.printStackTrace();
> }
> Here's how we're calling the ADODB dll:
> try {
> String connectStr = args[0];
> String queryStr = "select * from authors";
> getCommand(connectStr, queryStr);
> // getRS(connectStr, queryStr);
> } catch (Throwable t) {
> int errorInfo = getErrorInfo();
> System.out.println("The return was error Info from Connection:" +
errorInfo);
> t.printStackTrace();
> }
> public static void getCommand(String con, String query) throws
COMException // throws
> // Exception
> {
> System.out.println("Command+Connection -> Recordset");
> Connection c = new Connection("ADODB.Connection");
> c.setConnectionString(con);
> c.Open();
> Command comm = new Command("ADODB.Command");
> comm.setActiveConnection(c);
> comm.setCommandType(CommandTypeEnum.adCmdText);
> comm.setCommandText(query);
> Recordset rs = comm.Execute();
> printRS(rs);
> comm.close();
> c.Close();
> }
> Here's how we're going after the error information:
> private static int getErrorInfo() {
> int ret = 0;
> try {
> FuncPtr getErrInfo = new FuncPtr("OLEAUT32.DLL", "GetErrorInfo");
> ret = getErrInfo.invoke(0, 0, ReturnFlags.FAIL_ON_FALSE);
> } catch (COMException e) {
> // TODO Auto-generated catch block
> e.printStackTrace();
> }
> return ret;
> }
>
>
>
> ---------------------------------
> Talk is cheap. Use Yahoo! Messenger to make PC-to-Phone calls. Great rates
starting at 1¢/min.
>
>
>
> ---------------------------------
> How low will we go? Check out Yahoo! Messenger's low PC-to-Phone call
rates.
>
>
>  __________________________________________________
> Do You Yahoo!?
> Tired of spam?  Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com