This is an automated email from the ASF dual-hosted git repository.

leginee pushed a commit to branch trunk-dbaccess-wizard-fixes
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 536c01781ffc328a3102d1a07b58da2c14f07e9c
Author: Peter Kovacs <[email protected]>
AuthorDate: Fri Aug 14 22:00:42 2026 +0200

    Report wizard start failures instead of silently doing nothing
    
    Issue 80338 comment 21 reports that the table wizard dialog simply does not
    appear, with no error message of any kind, and correctly guesses that the
    underlying error "is caught and ignored somewhere (libdbaxml680li.so?)".  
It is
    in dbaxml, and there are two independent silent paths.
    
    dbaccess/source/filter/xml/dbloader2.cxx, started automatically after a new
    database document is created:
    
        if ( m_aContext.createComponentWithArguments(
                 "com.sun.star.wizards.table.CallTableWizard", aWizArgs, 
xTableWizard ) )
            xTableWizard->trigger( "start" );
        }
        catch(const Exception&)
        {
            OSL_ENSURE(sal_False, "caught an exception while starting the table 
wizard!");
        }
    
    createComponentWithArguments() returns false rather than throwing when the
    service is not registered, and there is no else branch -- so nothing 
happens and
    nothing is said.  When creation does throw, which is the case in the 
original
    report (the wizard is a Java component and JNI_proxy.dispatch_call cannot be
    linked), the exception is discarded by OSL_ENSURE, which is debug-only and
    therefore does nothing in a product build.
    
    dbaccess/source/ui/misc/linkeddocuments.cxx, behind "Use Wizard to Create
    Table/Query/Form/Report", has the same second problem: UNO_QUERY_THROW does 
turn
    a missing service into an exception, but the catch discards it with
    DBG_UNHANDLED_EXCEPTION, also debug-only.
    
    Both now show the error.  Notes on the shape of the fix:
    
      - OnStartTableWizard must not do modal UI inline.  It runs from a VCL user
        event, and m_xMySelf holds the loader alive across that event; a 
message box
        pumps a nested event loop, during which the document and frame creation 
the
        handler was posted from keeps running and can drop the last reference.  
So
        the error is collected first, all member state is settled -- with a 
local
        keep-alive making it safe to release the self-reference early -- and 
only
        then reported, so nothing touches the object after the nested loop.
        linkeddocuments.cxx needs none of this: it is a direct UI action with a 
real
        parent window and no self-reference.
    
      - The text displayed is the underlying error's own message, so this adds 
no
        new localizable string and needs no translation work.  A properly 
worded and
        translated wrapper would be nicer and is a reasonable follow-up; it is
        deliberately not done here to keep the change small.
    
      - ErrorBox rather than the InteractionHandler or dbaui::showError, both of
        which would have stayed silent for this class of error.  uui's
        handleRequest_impl matches specific request types and returns false for
        anything else (after another debug-only OSL_ENSURE), and showError is
        documented as showing nothing when the SQLExceptionInfo is not valid, 
which
        a plain RuntimeException is not.  ErrorBox is already reachable from 
both
        libraries -- each file already includes vcl/msgbox.hxx.
    
      - The exception must not be rethrown.  An escaping exception reaches
        Desktop::Main's catch-all, which calls FatalError() and then _exit() --
        turning a silent no-op into killing the office with unsaved work in 
other
        windows.
    
      - The reporting itself is wrapped in a catch-all so that reporting an 
error
        can never replace it with a different one, and it takes the solar mutex
        because in the throwing path the caller's guard has already been 
unwound.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
---
 main/dbaccess/source/filter/xml/dbloader2.cxx    | 64 +++++++++++++++++++++++-
 main/dbaccess/source/ui/misc/linkeddocuments.cxx | 26 ++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/main/dbaccess/source/filter/xml/dbloader2.cxx 
b/main/dbaccess/source/filter/xml/dbloader2.cxx
index 4cc54758b9..8f34b63b8b 100644
--- a/main/dbaccess/source/filter/xml/dbloader2.cxx
+++ b/main/dbaccess/source/filter/xml/dbloader2.cxx
@@ -602,10 +602,52 @@ void SAL_CALL DBContentLoader::load(const Reference< 
XFrame > & rFrame, const ::
 void DBContentLoader::cancel(void) throw()
 {
 }
+// 
-----------------------------------------------------------------------------
+namespace
+{
+    /** tell the user that the table wizard could not be started
+
+        Both ways this can fail used to be completely silent, which is issue
+        80338 (comment 21): the wizard dialog simply never appeared, with no
+        error message of any kind.
+
+        1. The service is not registered at all.  
createComponentWithArguments()
+           returns false in that case rather than throwing, and the caller had 
no
+           else branch, so nothing happened and nothing was said.
+        2. Creation threw -- e.g. the Java component is registered but the
+           java_uno bridge cannot be loaded, which is the case in the original
+           report.  That was discarded by a debug-only OSL_ENSURE, so a product
+           build again showed nothing.
+
+        The text shown is the underlying error's own message, so this needs no
+        new localizable string.  Reporting an error must never itself throw and
+        replace the error being reported, hence the catch-all.
+    */
+    void lcl_reportWizardStartFailure( const ::rtl::OUString& _rMessage )
+    {
+        try
+        {
+            ::rtl::OUString sMessage( _rMessage );
+            if ( !sMessage.getLength() )
+                sMessage = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+                    "The table wizard could not be started." ) );
+
+            // the solar mutex is not necessarily held here: when creation 
threw,
+            // the guard in the caller's try block has already been unwound
+            ::vos::OGuard aGuard( Application::GetSolarMutex() );
+            ErrorBox( NULL, WB_OK, sMessage ).Execute();
+        }
+        catch( const Exception& )
+        {
+        }
+    }
+}
+
 // 
-----------------------------------------------------------------------------
 IMPL_LINK( DBContentLoader, OnStartTableWizard, void*, /*NOTINTERESTEDIN*/ )
 {
        m_nStartWizard = 0;
+    ::rtl::OUString sWizardError;
        try
        {
         Sequence< Any > aWizArgs(1);
@@ -618,12 +660,32 @@ IMPL_LINK( DBContentLoader, OnStartTableWizard, void*, 
/*NOTINTERESTEDIN*/ )
         Reference< XJobExecutor > xTableWizard;
         if ( m_aContext.createComponentWithArguments( 
"com.sun.star.wizards.table.CallTableWizard", aWizArgs, xTableWizard ) )
                        
xTableWizard->trigger(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("start")));
+        else
+            sWizardError = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+                "The table wizard is not available: the service "
+                "com.sun.star.wizards.table.CallTableWizard could not be 
created." ) );
        }
-       catch(const Exception&)
+       catch(const Exception& e)
        {
                OSL_ENSURE(sal_False, "caught an exception while starting the 
table wizard!");
+        sWizardError = e.Message;
+        if ( !sWizardError.getLength() )
+            sWizardError = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+                "The table wizard could not be started." ) );
        }
+
+    // Nothing may touch this object once an error is reported: a message box
+    // pumps a nested event loop, during which the document and frame creation
+    // this handler was posted from can still run and drop the last reference.
+    // So settle all member state first -- the local keep-alive is what makes 
it
+    // safe to release the self-reference here rather than at the end -- and 
only
+    // then report.
+    Reference< XFrameLoader > xKeepAlive( m_xMySelf );
        m_xMySelf = NULL;
+
+    if ( sWizardError.getLength() )
+        lcl_reportWizardStartFailure( sWizardError );
+
        return 0L;
 }
 }
diff --git a/main/dbaccess/source/ui/misc/linkeddocuments.cxx 
b/main/dbaccess/source/ui/misc/linkeddocuments.cxx
index f55cfb57f3..3078525187 100644
--- a/main/dbaccess/source/ui/misc/linkeddocuments.cxx
+++ b/main/dbaccess/source/ui/misc/linkeddocuments.cxx
@@ -292,6 +292,32 @@ namespace dbaui
                catch(const Exception& e)
                {
             DBG_UNHANDLED_EXCEPTION();
+
+            // DBG_UNHANDLED_EXCEPTION is debug-only, so in a product build 
this
+            // used to be completely silent: picking "Use Wizard to Create ..."
+            // did nothing at all, with no error message.  That is issue 80338
+            // (comment 21) -- there the wizard is a Java component and 
creation
+            // fails when the java_uno bridge cannot be loaded; it fails the 
same
+            // way whenever the wizard service is simply not registered, 
because
+            // UNO_QUERY_THROW above turns the resulting empty reference into 
an
+            // exception.  Show the error's own message rather than inventing a
+            // new localizable string.
+            // Lead with the service name.  The underlying text is a low-level 
UNO
+            // message -- for a service that is not registered, UNO_QUERY_THROW
+            // above produces "unsatisfied query for interface of type
+            // com.sun.star.task.XJobExecutor!", which never mentions which
+            // component is missing, and that is the one fact worth knowing.
+            ::rtl::OUString sMessage( ::rtl::OUString::createFromAscii( 
_pWizardService ) );
+            if ( e.Message.getLength() )
+                sMessage += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( 
":\n" ) ) + e.Message;
+            try
+            {
+                ErrorBox( m_pDialogParent, WB_OK, sMessage ).Execute();
+            }
+            catch( const Exception& )
+            {
+                // reporting an error must not replace it with another one
+            }
                }
        }
        //------------------------------------------------------------------

Reply via email to