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 + } } } //------------------------------------------------------------------
