forked from amazingfate/loongoffice
... in ImplRepository::~ImplRepository.
Running on Windows:
make UITest_manual_tests UITEST_TEST_NAME=calc.ManualCalcTests.test_cell_recalc
fails:
...
Execution time for calc.ManualCalcTests.test_cell_recalc: 8.876
tearDown: calling terminate()...
...done
ERROR
======================================================================
ERROR: test_cell_recalc (calc.ManualCalcTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\lo\src\core\uitest\uitest\framework.py", line 46, in tearDown
self.connection.tearDown()
File "C:\lo\src\core\uitest\libreoffice\connection.py", line 178, in tearDown
self.connection.tearDown()
File "C:\lo\src\core\uitest\libreoffice\connection.py", line 138, in tearDown
raise Exception("Exit status indicates failure: " + str(ret))
Exception: Exit status indicates failure: 3221225477
----------------------------------------------------------------------
Ran 1 test in 131.616s
FAILED (errors=1)
Tests run: 1
Tests failed: 0
Tests errors: 1
Tests skipped: 0
The call stack at the point of failure is
sblo.dll!std::unique_ptr<SbxAppData,std::default_delete<SbxAppData>>::operator*() Line 1886
sblo.dll!GetSbxData_Impl() Line 110
sblo.dll!SbxBase::RemoveFactory(const SbxFactory * pFac) Line 122
sblo.dll!StarBASIC::~StarBASIC() Line 964
sblo.dll!StarBASIC::`vbase destructor'()
sblo.dll!StarBASIC::`vector deleting destructor'(unsigned int)
tllo.dll!SvRefBase::ReleaseRef() Line 163
sblo.dll!tools::SvRef<StarBASIC>::~SvRef<StarBASIC>() Line 56
sblo.dll!BasicLibInfo::~BasicLibInfo()
sblo.dll!BasicLibInfo::`scalar deleting destructor'(unsigned int)
sblo.dll!std::default_delete<BasicLibInfo>::operator()(BasicLibInfo * _Ptr) Line 1765
sblo.dll!std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>::~unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>() Line 1875
sblo.dll!std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>::`scalar deleting destructor'(unsigned int)
sblo.dll!std::_Default_allocator_traits<std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>::destroy<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>(std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>> & __formal, std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>> * const _Ptr) Line 677
sblo.dll!std::_Destroy_range<std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>(std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>> * _First, std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>> * const _Last, std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>> & _Al) Line 951
sblo.dll!std::vector<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>,std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>::_Destroy(std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>> * _First, std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>> * _Last) Line 1616
sblo.dll!std::vector<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>,std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>::_Tidy() Line 1698
sblo.dll!std::vector<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>,std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>::~vector<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>,std::allocator<std::unique_ptr<BasicLibInfo,std::default_delete<BasicLibInfo>>>>() Line 674
sblo.dll!BasicManagerImpl::~BasicManagerImpl()
sblo.dll!BasicManagerImpl::`scalar deleting destructor'(unsigned int)
sblo.dll!std::default_delete<BasicManagerImpl>::operator()(BasicManagerImpl * _Ptr) Line 1765
sblo.dll!std::unique_ptr<BasicManagerImpl,std::default_delete<BasicManagerImpl>>::~unique_ptr<BasicManagerImpl,std::default_delete<BasicManagerImpl>>() Line 1875
sblo.dll!BasicManager::~BasicManager() Line 824
sblo.dll!BasicManager::`vector deleting destructor'(unsigned int)
sblo.dll!std::default_delete<BasicManager>::operator()(BasicManager * _Ptr) Line 1765
sblo.dll!std::unique_ptr<BasicManager,std::default_delete<BasicManager>>::~unique_ptr<BasicManager,std::default_delete<BasicManager>>() Line 1875
sblo.dll!std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>::~pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>()
sblo.dll!std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>::`scalar deleting destructor'(unsigned int)
sblo.dll!std::_Default_allocator_traits<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>::destroy<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & __formal, std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>> * const _Ptr) Line 677
sblo.dll!std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>::_Freenode<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & _Al, std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *> * _Ptr) Line 379
sblo.dll!std::_Tree<std::_Tmap_traits<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>,0>>::_Erase_unchecked(std::_Tree_unchecked_const_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>,std::_Iterator_base0> _Where) Line 1389
sblo.dll!std::_Tree<std::_Tmap_traits<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>,0>>::erase<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>>,void>(std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>> _Where) Line 1417
sblo.dll!basic::ImplRepository::Notify(SfxBroadcaster & _rBC, const SfxHint & _rHint) Line 580
svllo.dll!SfxBroadcaster::Broadcast(const SfxHint & rHint) Line 50
sblo.dll!BasicManager::~BasicManager() Line 823
sblo.dll!BasicManager::`vector deleting destructor'(unsigned int)
sblo.dll!std::default_delete<BasicManager>::operator()(BasicManager * _Ptr) Line 1765
sblo.dll!std::unique_ptr<BasicManager,std::default_delete<BasicManager>>::~unique_ptr<BasicManager,std::default_delete<BasicManager>>() Line 1875
sblo.dll!std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>::~pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>()
sblo.dll!std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>::`scalar deleting destructor'(unsigned int)
sblo.dll!std::_Default_allocator_traits<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>::destroy<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & __formal, std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>> * const _Ptr) Line 677
sblo.dll!std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>::_Freenode<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & _Al, std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *> * _Ptr) Line 379
sblo.dll!std::_Tree_val<std::_Tree_simple_types<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>::_Erase_tree<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & _Al, std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *> * _Rootnode) Line 745
sblo.dll!std::_Tree_val<std::_Tree_simple_types<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>::_Erase_head<std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>>>(std::allocator<std::_Tree_node<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>,void *>> & _Al) Line 753
sblo.dll!std::_Tree<std::_Tmap_traits<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>,0>>::~_Tree<std::_Tmap_traits<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>,0>>() Line 1191
sblo.dll!std::map<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>::~map<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>,std::less<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface>>,std::allocator<std::pair<com::sun:⭐:uno::Reference<com::sun:⭐:uno::XInterface> const ,std::unique_ptr<BasicManager,std::default_delete<BasicManager>>>>>()
sblo.dll!basic::ImplRepository::~ImplRepository()
sblo.dll!`basic::ImplRepository::Instance'::`2'::`dynamic atexit destructor for 'repository''()
ucrtbased.dll!_execute_onexit_table::__l2::<lambda>() Line 206
ucrtbased.dll!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) &,void <lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, _execute_onexit_table::__l2::int <lambda>(void) & action, __acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 204
ucrtbased.dll!__acrt_lock_and_call<int <lambda>(void)>(const __acrt_lock_id lock_id, _execute_onexit_table::__l2::int <lambda>(void) && action) Line 975
ucrtbased.dll!_execute_onexit_table(_onexit_table_t * table) Line 231
sblo.dll!__scrt_dllmain_uninitialize_c() Line 399
sblo.dll!dllmain_crt_process_detach(const bool is_terminating) Line 182
sblo.dll!dllmain_crt_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 220
sblo.dll!dllmain_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 293
sblo.dll!_DllMainCRTStartup(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 335
ntdll.dll!LdrpCallInitRoutine()
ntdll.dll!LdrShutdownProcess()
ntdll.dll!RtlExitUserProcess()
kernel32.dll!ExitProcessImplementation()
ucrtbased.dll!exit_or_terminate_process(const unsigned int return_code) Line 144
ucrtbased.dll!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 282
ucrtbased.dll!exit(int return_code) Line 294
soffice.bin!__scrt_common_main_seh() Line 297
soffice.bin!__scrt_common_main() Line 331
soffice.bin!mainCRTStartup() Line 17
kernel32.dll!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()
Two problems here:
1. Deleting a function-local static ImplRepository object happens after
BASIC_DLL destruction either in SfxApplication::~SfxApplication or in
MacroSnippet::~MacroSnippet, so BasicManager dtor indirectly trying to
access BASIC_DLL segfaults.
2. Implicit clearing of m_aStore in ImplRepository dtor calls dtors of
owned BasicManager objects, which in turn notify parent ImplRepository,
which again deletes the objects.
This change limits lifetime of ImplRepository object with SbxAppData
in BASIC_DLL, and avoids "owned BasicManager is deleting" notifications
in its dtor.
In dbaccess_complex test, ODatabaseContext accesses ImplRepository
instance independently of SfxAppData_Impl lifetime: the latter is
created before the former is created (and accesses ImplRepository
instance first time), and destroyed before the former is destroyed
(and accesses ImplRepository last time). So BASIC_DLL lifetime made
ref-counted, to allow correct sharing of common instance between
objects with independent lifetime.
See also commit 3ebf6a090b227c0097ff8668fe023e7bdbdadc5d.
Change-Id: I2ca36a87ddaf669557b3c3c7678e3d74aae66cce
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/85892
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Tested-by: Mike Kaganski <mike.kaganski@collabora.com>
627 lines
24 KiB
C++
627 lines
24 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <basic/basicmanagerrepository.hxx>
|
|
#include <basic/basmgr.hxx>
|
|
#include <scriptcont.hxx>
|
|
#include <dlgcont.hxx>
|
|
#include <sbintern.hxx>
|
|
#include <sbxbase.hxx>
|
|
|
|
#include <com/sun/star/document/XStorageBasedDocument.hpp>
|
|
#include <com/sun/star/document/XEmbeddedScripts.hpp>
|
|
#include <com/sun/star/frame/Desktop.hpp>
|
|
#include <svtools/ehdl.hxx>
|
|
#include <svtools/sfxecode.hxx>
|
|
#include <unotools/pathoptions.hxx>
|
|
#include <svl/hint.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <tools/debug.hxx>
|
|
#include <tools/diagnose_ex.h>
|
|
#include <tools/urlobj.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/documentinfo.hxx>
|
|
#include <unotools/eventlisteneradapter.hxx>
|
|
|
|
#include <sot/storage.hxx>
|
|
|
|
#include <map>
|
|
|
|
|
|
namespace basic
|
|
{
|
|
using ::com::sun::star::uno::Reference;
|
|
using ::com::sun::star::uno::XComponentContext;
|
|
using ::com::sun::star::frame::XModel;
|
|
using ::com::sun::star::frame::Desktop;
|
|
using ::com::sun::star::uno::XInterface;
|
|
using ::com::sun::star::uno::UNO_QUERY;
|
|
using ::com::sun::star::embed::XStorage;
|
|
using ::com::sun::star::script::XPersistentLibraryContainer;
|
|
using ::com::sun::star::uno::UNO_QUERY_THROW;
|
|
using ::com::sun::star::uno::Exception;
|
|
using ::com::sun::star::document::XStorageBasedDocument;
|
|
using ::com::sun::star::document::XEmbeddedScripts;
|
|
|
|
typedef std::map< Reference< XInterface >, std::unique_ptr<BasicManager> > BasicManagerStore;
|
|
|
|
typedef std::vector< BasicManagerCreationListener* > CreationListeners;
|
|
|
|
class ImplRepository : public ::utl::OEventListenerAdapter, public SfxListener, public SvRefBase
|
|
{
|
|
private:
|
|
ImplRepository();
|
|
~ImplRepository();
|
|
|
|
private:
|
|
BasicManagerStore m_aStore;
|
|
CreationListeners m_aCreationListeners;
|
|
|
|
public:
|
|
static ImplRepository& Instance();
|
|
|
|
BasicManager* getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel );
|
|
BasicManager* getOrCreateApplicationBasicManager();
|
|
static BasicManager* getApplicationBasicManager();
|
|
static void setApplicationBasicManager( std::unique_ptr<BasicManager> _pBasicManager );
|
|
void registerCreationListener( BasicManagerCreationListener& _rListener );
|
|
void revokeCreationListener( BasicManagerCreationListener& _rListener );
|
|
|
|
private:
|
|
/** retrieves the location at which the BasicManager for the given model
|
|
is stored.
|
|
|
|
If previously, the BasicManager for this model has never been requested,
|
|
then the model is added to the map, with an initial NULL BasicManager.
|
|
|
|
@param _rxDocumentModel
|
|
the model whose BasicManager's location is to be retrieved. Must not be <NULL/>.
|
|
|
|
@precond
|
|
our mutex is locked
|
|
*/
|
|
BasicManagerStore::iterator
|
|
impl_getLocationForModel( const Reference< XModel >& _rxDocumentModel );
|
|
|
|
/** tests if there is a location set at which the BasicManager for the given model
|
|
is stored.
|
|
|
|
@param _rxDocumentModel
|
|
the model whose BasicManager's location is to be retrieved. Must not be <NULL/>.
|
|
|
|
@precond
|
|
our mutex is locked
|
|
*/
|
|
bool impl_hasLocationForModel( const Reference< XModel >& _rxDocumentModel ) const;
|
|
|
|
/** creates a new BasicManager instance for the given model
|
|
|
|
@param _out_rpBasicManager
|
|
reference to the pointer variable that will hold the new
|
|
BasicManager.
|
|
|
|
@param _rxDocumentModel
|
|
the model whose BasicManager will be created. Must not be <NULL/>.
|
|
*/
|
|
bool impl_createManagerForModel(
|
|
BasicManagerStore::iterator location,
|
|
const Reference< XModel >& _rxDocumentModel );
|
|
|
|
/** creates the application-wide BasicManager
|
|
*/
|
|
BasicManager* impl_createApplicationBasicManager();
|
|
|
|
/** notifies all listeners which expressed interest in the creation of BasicManager instances.
|
|
*/
|
|
void impl_notifyCreationListeners(
|
|
const Reference< XModel >& _rxDocumentModel,
|
|
BasicManager& _rManager
|
|
);
|
|
|
|
/** retrieves the current storage of a given document
|
|
|
|
@param _rxDocument
|
|
the document whose storage is to be retrieved.
|
|
|
|
@param _out_rStorage
|
|
takes the storage upon successful return. Note that this might be <NULL/> even
|
|
if <TRUE/> is returned. In this case, the document has not yet been saved.
|
|
|
|
@return
|
|
<TRUE/> if the storage could be successfully retrieved (in which case
|
|
<arg>_out_rStorage</arg> might or might not be <NULL/>), <FALSE/> otherwise.
|
|
In the latter case, processing this document should stop.
|
|
*/
|
|
static bool impl_getDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, Reference< XStorage >& _out_rStorage );
|
|
|
|
/** retrieves the containers for Basic and Dialog libraries for a given document
|
|
|
|
@param _rxDocument
|
|
the document whose containers are to be retrieved.
|
|
|
|
@param _out_rxBasicLibraries
|
|
takes the basic library container upon successful return
|
|
|
|
@param _out_rxDialogLibraries
|
|
takes the dialog library container upon successful return
|
|
|
|
@return
|
|
<TRUE/> if and only if both containers exist, and could successfully be retrieved
|
|
*/
|
|
static bool impl_getDocumentLibraryContainers_nothrow(
|
|
const Reference< XModel >& _rxDocument,
|
|
Reference< XPersistentLibraryContainer >& _out_rxBasicLibraries,
|
|
Reference< XPersistentLibraryContainer >& _out_rxDialogLibraries
|
|
);
|
|
|
|
/** initializes the given library containers, which belong to a document
|
|
*/
|
|
static void impl_initDocLibraryContainers_nothrow(
|
|
const Reference< XPersistentLibraryContainer >& _rxBasicLibraries,
|
|
const Reference< XPersistentLibraryContainer >& _rxDialogLibraries
|
|
);
|
|
|
|
// OEventListenerAdapter overridables
|
|
virtual void _disposing( const css::lang::EventObject& _rSource ) override;
|
|
|
|
// SfxListener overridables
|
|
virtual void Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint ) override;
|
|
|
|
/** removes the Model/BasicManager pair given by iterator from our store
|
|
*/
|
|
void impl_removeFromRepository( const BasicManagerStore::iterator& _pos );
|
|
|
|
private:
|
|
StarBASIC* impl_getDefaultAppBasicLibrary();
|
|
};
|
|
|
|
ImplRepository::ImplRepository()
|
|
{
|
|
}
|
|
|
|
ImplRepository::~ImplRepository()
|
|
{
|
|
// Avoid double-delete of managers when they are destroyed in our dtor, and start notify us
|
|
for (auto& it : m_aStore)
|
|
EndListening(*it.second);
|
|
}
|
|
|
|
ImplRepository& ImplRepository::Instance()
|
|
{
|
|
tools::SvRef<SvRefBase>& repository = GetSbxData_Impl().mrImplRepository;
|
|
{
|
|
static osl::Mutex aMutex;
|
|
osl::MutexGuard aGuard(aMutex);
|
|
if (!repository)
|
|
repository = new ImplRepository;
|
|
}
|
|
return *static_cast<ImplRepository*>(repository.get());
|
|
}
|
|
|
|
BasicManager* ImplRepository::getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel )
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
/* #163556# (DR) - This function may be called recursively while
|
|
constructing the Basic manager and loading the Basic storage. By
|
|
passing the map entry received from impl_getLocationForModel() to
|
|
the function impl_createManagerForModel(), the new Basic manager
|
|
will be put immediately into the map of existing Basic managers,
|
|
thus a recursive call of this function will find and return it
|
|
without creating another instance.
|
|
*/
|
|
auto const loc = impl_getLocationForModel( _rxDocumentModel );
|
|
if (loc->second != nullptr)
|
|
return loc->second.get();
|
|
if (impl_createManagerForModel(loc, _rxDocumentModel))
|
|
return loc->second.get();
|
|
return nullptr;
|
|
}
|
|
|
|
BasicManager* ImplRepository::getOrCreateApplicationBasicManager()
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
BasicManager* pAppManager = GetSbData()->pAppBasMgr.get();
|
|
if (pAppManager == nullptr)
|
|
pAppManager = impl_createApplicationBasicManager();
|
|
return pAppManager;
|
|
}
|
|
|
|
BasicManager* ImplRepository::getApplicationBasicManager()
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
return GetSbData()->pAppBasMgr.get();
|
|
}
|
|
|
|
void ImplRepository::setApplicationBasicManager( std::unique_ptr<BasicManager> _pBasicManager )
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
GetSbData()->pAppBasMgr = std::move(_pBasicManager);
|
|
}
|
|
|
|
|
|
BasicManager* ImplRepository::impl_createApplicationBasicManager()
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
OSL_PRECOND(getApplicationBasicManager() == nullptr, "ImplRepository::impl_createApplicationBasicManager: there already is one!");
|
|
|
|
// Determine Directory
|
|
SvtPathOptions aPathCFG;
|
|
OUString aAppBasicDir( aPathCFG.GetBasicPath() );
|
|
if ( aAppBasicDir.isEmpty() )
|
|
{
|
|
aPathCFG.SetBasicPath("$(prog)");
|
|
}
|
|
|
|
// Create basic and load it
|
|
// AppBasicDir is now a PATH
|
|
INetURLObject aAppBasic( SvtPathOptions().SubstituteVariable("$(progurl)") );
|
|
aAppBasic.insertName( Application::GetAppName() );
|
|
|
|
BasicManager* pBasicManager = new BasicManager( new StarBASIC, &aAppBasicDir );
|
|
setApplicationBasicManager( std::unique_ptr<BasicManager>(pBasicManager) );
|
|
|
|
// The first dir in the path as destination:
|
|
OUString aFileName( aAppBasic.getName() );
|
|
aAppBasic = INetURLObject( aAppBasicDir.getToken(1, ';') );
|
|
DBG_ASSERT(aAppBasic.GetProtocol() != INetProtocol::NotValid,
|
|
OString("Invalid URL: \"" +
|
|
OUStringToOString(aAppBasicDir, osl_getThreadTextEncoding()) +
|
|
"\"").getStr());
|
|
aAppBasic.insertName( aFileName );
|
|
pBasicManager->SetStorageName( aAppBasic.PathToFileName() );
|
|
|
|
// Basic container
|
|
SfxScriptLibraryContainer* pBasicCont = new SfxScriptLibraryContainer( Reference< XStorage >() );
|
|
Reference< XPersistentLibraryContainer > xBasicCont( pBasicCont );
|
|
pBasicCont->setBasicManager( pBasicManager );
|
|
|
|
// Dialog container
|
|
SfxDialogLibraryContainer* pDialogCont = new SfxDialogLibraryContainer( Reference< XStorage >() );
|
|
Reference< XPersistentLibraryContainer > xDialogCont( pDialogCont );
|
|
|
|
LibraryContainerInfo aInfo( xBasicCont, xDialogCont, static_cast< OldBasicPassword* >( pBasicCont ) );
|
|
pBasicManager->SetLibraryContainerInfo( aInfo );
|
|
|
|
// global constants
|
|
|
|
// StarDesktop
|
|
Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
|
|
pBasicManager->SetGlobalUNOConstant( "StarDesktop", css::uno::Any( Desktop::create(xContext)));
|
|
|
|
// (BasicLibraries and DialogLibraries have automatically been added in SetLibraryContainerInfo)
|
|
|
|
// notify
|
|
impl_notifyCreationListeners( nullptr, *pBasicManager );
|
|
|
|
// outta here
|
|
return pBasicManager;
|
|
}
|
|
|
|
|
|
void ImplRepository::registerCreationListener( BasicManagerCreationListener& _rListener )
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
m_aCreationListeners.push_back( &_rListener );
|
|
}
|
|
|
|
|
|
void ImplRepository::revokeCreationListener( BasicManagerCreationListener& _rListener )
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
CreationListeners::iterator pos = std::find( m_aCreationListeners.begin(), m_aCreationListeners.end(), &_rListener );
|
|
if ( pos != m_aCreationListeners.end() )
|
|
m_aCreationListeners.erase( pos );
|
|
else {
|
|
OSL_FAIL( "ImplRepository::revokeCreationListener: listener is not registered!" );
|
|
}
|
|
}
|
|
|
|
|
|
void ImplRepository::impl_notifyCreationListeners( const Reference< XModel >& _rxDocumentModel, BasicManager& _rManager )
|
|
{
|
|
for (auto const& creationListener : m_aCreationListeners)
|
|
{
|
|
creationListener->onBasicManagerCreated( _rxDocumentModel, _rManager );
|
|
}
|
|
}
|
|
|
|
|
|
StarBASIC* ImplRepository::impl_getDefaultAppBasicLibrary()
|
|
{
|
|
BasicManager* pAppManager = getOrCreateApplicationBasicManager();
|
|
|
|
StarBASIC* pAppBasic = pAppManager ? pAppManager->GetLib(0) : nullptr;
|
|
DBG_ASSERT( pAppBasic != nullptr, "impl_getApplicationBasic: unable to determine the default application's Basic library!" );
|
|
return pAppBasic;
|
|
}
|
|
|
|
BasicManagerStore::iterator ImplRepository::impl_getLocationForModel( const Reference< XModel >& _rxDocumentModel )
|
|
{
|
|
Reference< XInterface > xNormalized( _rxDocumentModel, UNO_QUERY );
|
|
DBG_ASSERT( _rxDocumentModel.is(), "ImplRepository::impl_getLocationForModel: invalid model!" );
|
|
|
|
return m_aStore.try_emplace(xNormalized).first;
|
|
}
|
|
|
|
bool ImplRepository::impl_hasLocationForModel( const Reference< XModel >& _rxDocumentModel ) const
|
|
{
|
|
Reference< XInterface > xNormalized( _rxDocumentModel, UNO_QUERY );
|
|
DBG_ASSERT( _rxDocumentModel.is(), "ImplRepository::impl_getLocationForModel: invalid model!" );
|
|
|
|
return m_aStore.find(xNormalized) != m_aStore.end();
|
|
}
|
|
|
|
void ImplRepository::impl_initDocLibraryContainers_nothrow( const Reference< XPersistentLibraryContainer >& _rxBasicLibraries, const Reference< XPersistentLibraryContainer >& _rxDialogLibraries )
|
|
{
|
|
OSL_PRECOND( _rxBasicLibraries.is() && _rxDialogLibraries.is(),
|
|
"ImplRepository::impl_initDocLibraryContainers_nothrow: illegal library containers, this will crash!" );
|
|
|
|
try
|
|
{
|
|
// ensure there's a standard library in the basic container
|
|
OUString aStdLibName( "Standard" );
|
|
if ( !_rxBasicLibraries->hasByName( aStdLibName ) )
|
|
{
|
|
_rxBasicLibraries->createLibrary( aStdLibName );
|
|
}
|
|
// as well as in the dialog container
|
|
if ( !_rxDialogLibraries->hasByName( aStdLibName ) )
|
|
{
|
|
_rxDialogLibraries->createLibrary( aStdLibName );
|
|
}
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("basic");
|
|
}
|
|
}
|
|
|
|
bool ImplRepository::impl_createManagerForModel( BasicManagerStore::iterator location, const Reference< XModel >& _rxDocumentModel )
|
|
{
|
|
auto & _out_rpBasicManager = location->second;
|
|
|
|
StarBASIC* pAppBasic = impl_getDefaultAppBasicLibrary();
|
|
|
|
_out_rpBasicManager = nullptr;
|
|
Reference< XStorage > xStorage;
|
|
if ( !impl_getDocumentStorage_nothrow( _rxDocumentModel, xStorage ) )
|
|
{
|
|
m_aStore.erase(location);
|
|
// the document is not able to provide the storage it is based on.
|
|
return false;
|
|
}
|
|
Reference< XPersistentLibraryContainer > xBasicLibs;
|
|
Reference< XPersistentLibraryContainer > xDialogLibs;
|
|
if ( !impl_getDocumentLibraryContainers_nothrow( _rxDocumentModel, xBasicLibs, xDialogLibs ) )
|
|
{
|
|
m_aStore.erase(location);
|
|
// the document does not have BasicLibraries and DialogLibraries
|
|
return false;
|
|
}
|
|
|
|
if ( xStorage.is() )
|
|
{
|
|
// load BASIC-manager
|
|
SfxErrorContext aErrContext( ERRCTX_SFX_LOADBASIC,
|
|
::comphelper::DocumentInfo::getDocumentTitle( _rxDocumentModel ) );
|
|
OUString aAppBasicDir = SvtPathOptions().GetBasicPath();
|
|
|
|
// Storage and BaseURL are only needed by binary documents!
|
|
tools::SvRef<SotStorage> xDummyStor = new SotStorage( OUString() );
|
|
_out_rpBasicManager.reset(new BasicManager( *xDummyStor, OUString() /* TODO/LATER: xStorage */,
|
|
pAppBasic,
|
|
&aAppBasicDir, true ));
|
|
if ( !_out_rpBasicManager->GetErrors().empty() )
|
|
{
|
|
// handle errors
|
|
std::vector<BasicError>& aErrors = _out_rpBasicManager->GetErrors();
|
|
for(const auto& rError : aErrors)
|
|
{
|
|
// show message to user
|
|
if ( ErrorHandler::HandleError( rError.GetErrorId() ) == DialogMask::ButtonsCancel )
|
|
{
|
|
// user wants to break loading of BASIC-manager
|
|
_out_rpBasicManager.reset();
|
|
xStorage.clear();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// not loaded?
|
|
if ( !xStorage.is() )
|
|
{
|
|
// create new BASIC-manager
|
|
StarBASIC* pBasic = new StarBASIC( pAppBasic );
|
|
pBasic->SetFlag( SbxFlagBits::ExtSearch );
|
|
_out_rpBasicManager.reset(new BasicManager( pBasic, nullptr, true ));
|
|
}
|
|
|
|
// knit the containers with the BasicManager
|
|
LibraryContainerInfo aInfo( xBasicLibs, xDialogLibs, dynamic_cast< OldBasicPassword* >( xBasicLibs.get() ) );
|
|
OSL_ENSURE( aInfo.mpOldBasicPassword, "ImplRepository::impl_createManagerForModel: wrong BasicLibraries implementation!" );
|
|
_out_rpBasicManager->SetLibraryContainerInfo( aInfo );
|
|
|
|
// initialize the containers
|
|
impl_initDocLibraryContainers_nothrow( xBasicLibs, xDialogLibs );
|
|
|
|
// so that also dialogs etc. could be 'qualified' addressed
|
|
_out_rpBasicManager->GetLib(0)->SetParent( pAppBasic );
|
|
|
|
// global properties in the document's Basic
|
|
_out_rpBasicManager->SetGlobalUNOConstant( "ThisComponent", css::uno::Any( _rxDocumentModel ) );
|
|
|
|
// notify
|
|
impl_notifyCreationListeners( _rxDocumentModel, *_out_rpBasicManager );
|
|
|
|
// register as listener for this model being disposed/closed
|
|
OSL_ENSURE( _rxDocumentModel.is(), "ImplRepository::impl_createManagerForModel: the document must be an XComponent!" );
|
|
assert(impl_hasLocationForModel(_rxDocumentModel));
|
|
startComponentListening( _rxDocumentModel );
|
|
|
|
bool bOk = false;
|
|
// startComponentListening may fail in a disposed _rxDocumentModel, in which case _out_rpBasicManager will be removed
|
|
// from the map and destroyed
|
|
if (impl_hasLocationForModel(_rxDocumentModel))
|
|
{
|
|
bOk = true;
|
|
// register as listener for the BasicManager being destroyed
|
|
StartListening( *_out_rpBasicManager );
|
|
}
|
|
|
|
// #i104876: Library container must not be modified just after
|
|
// creation. This happens as side effect when creating default
|
|
// "Standard" libraries and needs to be corrected here
|
|
xBasicLibs->setModified( false );
|
|
xDialogLibs->setModified( false );
|
|
return bOk;
|
|
}
|
|
|
|
bool ImplRepository::impl_getDocumentStorage_nothrow( const Reference< XModel >& _rxDocument, Reference< XStorage >& _out_rStorage )
|
|
{
|
|
_out_rStorage.clear();
|
|
try
|
|
{
|
|
Reference< XStorageBasedDocument > xStorDoc( _rxDocument, UNO_QUERY_THROW );
|
|
_out_rStorage.set( xStorDoc->getDocumentStorage() );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("basic");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ImplRepository::impl_getDocumentLibraryContainers_nothrow( const Reference< XModel >& _rxDocument,
|
|
Reference< XPersistentLibraryContainer >& _out_rxBasicLibraries, Reference< XPersistentLibraryContainer >& _out_rxDialogLibraries )
|
|
{
|
|
_out_rxBasicLibraries.clear();
|
|
_out_rxDialogLibraries.clear();
|
|
try
|
|
{
|
|
Reference< XEmbeddedScripts > xScripts( _rxDocument, UNO_QUERY_THROW );
|
|
_out_rxBasicLibraries.set( xScripts->getBasicLibraries(), UNO_QUERY_THROW );
|
|
_out_rxDialogLibraries.set( xScripts->getDialogLibraries(), UNO_QUERY_THROW );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("basic");
|
|
}
|
|
return _out_rxBasicLibraries.is() && _out_rxDialogLibraries.is();
|
|
}
|
|
|
|
|
|
void ImplRepository::impl_removeFromRepository( const BasicManagerStore::iterator& _pos )
|
|
{
|
|
OSL_PRECOND( _pos != m_aStore.end(), "ImplRepository::impl_removeFromRepository: invalid position!" );
|
|
|
|
std::unique_ptr<BasicManager> pManager = std::move(_pos->second);
|
|
Reference<XModel> xModel(_pos->first, UNO_QUERY);
|
|
|
|
// *first* remove from map (else Notify won't work properly)
|
|
m_aStore.erase( _pos );
|
|
|
|
EndListening( *pManager );
|
|
|
|
assert(xModel.is());
|
|
if (xModel.is())
|
|
stopComponentListening(xModel);
|
|
}
|
|
|
|
|
|
void ImplRepository::_disposing( const css::lang::EventObject& _rSource )
|
|
{
|
|
SolarMutexGuard g;
|
|
|
|
Reference< XInterface > xNormalizedSource( _rSource.Source, UNO_QUERY );
|
|
|
|
BasicManagerStore::iterator it = std::find_if(m_aStore.begin(), m_aStore.end(),
|
|
[&xNormalizedSource](BasicManagerStore::reference rEntry) {
|
|
return rEntry.first.get() == xNormalizedSource.get(); });
|
|
if (it != m_aStore.end())
|
|
{
|
|
impl_removeFromRepository( it );
|
|
return;
|
|
}
|
|
|
|
OSL_FAIL( "ImplRepository::_disposing: where does this come from?" );
|
|
}
|
|
|
|
|
|
void ImplRepository::Notify( SfxBroadcaster& _rBC, const SfxHint& _rHint )
|
|
{
|
|
if ( _rHint.GetId() != SfxHintId::Dying )
|
|
// not interested in
|
|
return;
|
|
|
|
BasicManager* pManager = dynamic_cast< BasicManager* >( &_rBC );
|
|
OSL_ENSURE( pManager, "ImplRepository::Notify: where does this come from?" );
|
|
|
|
BasicManagerStore::iterator it = std::find_if(m_aStore.begin(), m_aStore.end(),
|
|
[&pManager](BasicManagerStore::reference rEntry) { return rEntry.second.get() == pManager; });
|
|
if (it != m_aStore.end())
|
|
{
|
|
// a BasicManager which is still in our repository is being deleted.
|
|
// That's bad, since by definition, we *own* all instances in our
|
|
// repository.
|
|
OSL_FAIL( "ImplRepository::Notify: nobody should tamper with the managers, except ourself!" );
|
|
m_aStore.erase( it );
|
|
}
|
|
}
|
|
|
|
BasicManager* BasicManagerRepository::getDocumentBasicManager( const Reference< XModel >& _rxDocumentModel )
|
|
{
|
|
return ImplRepository::Instance().getDocumentBasicManager( _rxDocumentModel );
|
|
}
|
|
|
|
BasicManager* BasicManagerRepository::getApplicationBasicManager()
|
|
{
|
|
return ImplRepository::Instance().getOrCreateApplicationBasicManager();
|
|
}
|
|
|
|
void BasicManagerRepository::resetApplicationBasicManager()
|
|
{
|
|
ImplRepository::setApplicationBasicManager( nullptr );
|
|
}
|
|
|
|
void BasicManagerRepository::registerCreationListener( BasicManagerCreationListener& _rListener )
|
|
{
|
|
ImplRepository::Instance().registerCreationListener( _rListener );
|
|
}
|
|
|
|
void BasicManagerRepository::revokeCreationListener( BasicManagerCreationListener& _rListener )
|
|
{
|
|
ImplRepository::Instance().revokeCreationListener( _rListener );
|
|
}
|
|
|
|
} // namespace basic
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|