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