Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx
Warning:line 476, column 32
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name vbaeventshelper.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx

/home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include "vbaeventshelper.hxx"
21#include "excelvbahelper.hxx"
22
23#include <com/sun/star/awt/XTopWindow.hpp>
24#include <com/sun/star/awt/XTopWindowListener.hpp>
25#include <com/sun/star/awt/XWindowListener.hpp>
26#include <com/sun/star/frame/XBorderResizeListener.hpp>
27#include <com/sun/star/frame/XControllerBorder.hpp>
28#include <com/sun/star/script/ModuleType.hpp>
29#include <com/sun/star/script/vba/VBAEventId.hpp>
30#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
31#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
32#include <com/sun/star/table/XCellRange.hpp>
33#include <com/sun/star/util/XChangesListener.hpp>
34#include <com/sun/star/util/XChangesNotifier.hpp>
35
36#include <cppuhelper/implbase.hxx>
37#include <toolkit/helper/vclunohelper.hxx>
38#include <unotools/eventcfg.hxx>
39#include <vcl/event.hxx>
40#include <vcl/svapp.hxx>
41#include <vcl/window.hxx>
42#include <vbahelper/vbaaccesshelper.hxx>
43
44#include <docsh.hxx>
45#include <document.hxx>
46#include <cellsuno.hxx>
47#include <convuno.hxx>
48#include "vbaapplication.hxx"
49
50using namespace ::com::sun::star;
51using namespace ::com::sun::star::script::vba::VBAEventId;
52using namespace ::ooo::vba;
53
54namespace {
55
56/** Extracts a sheet index from the specified element of the passed sequence.
57 The element may be an integer, a Calc range or ranges object, or a VBA Range object.
58
59 @throws lang::IllegalArgumentException
60 @throws uno::RuntimeException
61*/
62SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex )
63{
64 VbaEventsHelperBase::checkArgument( rArgs, nIndex );
65
66 // first try to extract a sheet index
67 sal_Int32 nTab = -1;
68 if( rArgs[ nIndex ] >>= nTab )
69 {
70 if( (nTab < 0) || (nTab > MAXTAB) )
71 throw lang::IllegalArgumentException();
72 return static_cast< SCTAB >( nTab );
73 }
74
75 // try VBA Range object
76 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
77 if( xVbaRange.is() )
78 {
79 uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW );
80 // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface?
81 uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW );
82 // VBA sheet index is 1-based
83 return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 );
84 }
85
86 // try single UNO range object
87 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex );
88 if( xCellRangeAddressable.is() )
89 return xCellRangeAddressable->getRangeAddress().Sheet;
90
91 // at last, try UNO range list
92 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
93 if( xRanges.is() )
94 {
95 uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses();
96 if( aRangeAddresses.hasElements() )
97 return aRangeAddresses[ 0 ].Sheet;
98 }
99
100 throw lang::IllegalArgumentException();
101}
102
103/** Returns the AWT container window of the passed controller. */
104uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController )
105{
106 if( rxController.is() ) try
107 {
108 uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW );
109 return xFrame->getContainerWindow();
110 }
111 catch( uno::Exception& )
112 {
113 }
114 return nullptr;
115}
116
117} // namespace
118
119// This class is to process Workbook window related event
120class ScVbaEventListener : public ::cppu::WeakImplHelper< awt::XTopWindowListener,
121 awt::XWindowListener,
122 frame::XBorderResizeListener,
123 util::XChangesListener >
124{
125public:
126 ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell );
127
128 /** Starts listening to the passed document controller. */
129 void startControllerListening( const uno::Reference< frame::XController >& rxController );
130 /** Stops listening to the passed document controller. */
131 void stopControllerListening( const uno::Reference< frame::XController >& rxController );
132
133 // XTopWindowListener
134 virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) override;
135 virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) override;
136 virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) override;
137 virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) override;
138 virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) override;
139 virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) override;
140 virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) override;
141
142 // XWindowListener
143 virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) override;
144 virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) override;
145 virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) override;
146 virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) override;
147
148 // XBorderResizeListener
149 virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) override;
150
151 // XChangesListener
152 virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) override;
153
154 // XEventListener
155 virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) override;
156
157private:
158 /** Starts listening to the document model. */
159 void startModelListening();
160 /** Stops listening to the document model. */
161 void stopModelListening();
162
163 /** Returns the controller for the passed VCL window. */
164 uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const;
165
166 /** Calls the Workbook_Window[Activate|Deactivate] event handler. */
167 void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate );
168 /** Posts a Workbook_WindowResize user event. */
169 void postWindowResizeEvent( vcl::Window* pWindow );
170 /** Callback link for Application::PostUserEvent(). */
171 DECL_LINK( processWindowResizeEvent, void*, void )static void LinkStubprocessWindowResizeEvent(void *, void*); void
processWindowResizeEvent(void*)
;
172
173private:
174 typedef ::std::map< VclPtr<vcl::Window>, uno::Reference< frame::XController > > WindowControllerMap;
175
176 ::osl::Mutex maMutex;
177 ScVbaEventsHelper& mrVbaEvents;
178 uno::Reference< frame::XModel > mxModel;
179 ScDocShell* mpDocShell;
180 WindowControllerMap maControllers; /// Maps VCL top windows to their controllers.
181 std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent
182 VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation.
183 bool mbWindowResized; /// True = window resize system event processed.
184 bool mbBorderChanged; /// True = borders changed system event processed.
185 bool mbDisposed;
186};
187
188ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) :
189 mrVbaEvents( rVbaEvents ),
190 mxModel( rxModel ),
191 mpDocShell( pDocShell ),
192 mpActiveWindow( nullptr ),
193 mbWindowResized( false ),
194 mbBorderChanged( false ),
195 mbDisposed( !rxModel.is() )
196{
197 if( !mxModel.is() )
198 return;
199
200 startModelListening();
201 try
202 {
203 uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_SET_THROW );
204 startControllerListening( xController );
205 }
206 catch( uno::Exception& )
207 {
208 }
209}
210
211void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController )
212{
213 ::osl::MutexGuard aGuard( maMutex );
214
215 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
216 if( xWindow.is() )
217 try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {}
218
219 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
220 if( xTopWindow.is() )
221 try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {}
222
223 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
224 if( xControllerBorder.is() )
225 try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {}
226
227 if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) )
228 {
229 maControllers[ pWindow ] = rxController;
230 }
231}
232
233void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController )
234{
235 ::osl::MutexGuard aGuard( maMutex );
236
237 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
238 if( xWindow.is() )
239 try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {}
240
241 uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
242 if( xTopWindow.is() )
243 try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {}
244
245 uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
246 if( xControllerBorder.is() )
247 try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {}
248
249 if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) )
250 {
251 maControllers.erase( pWindow );
252 if( pWindow == mpActiveWindow )
253 mpActiveWindow = nullptr;
254 }
255}
256
257void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ )
258{
259}
260
261void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ )
262{
263}
264
265void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ )
266{
267}
268
269void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ )
270{
271}
272
273void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ )
274{
275}
276
277void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent )
278{
279 ::osl::MutexGuard aGuard( maMutex );
280
281 if( mbDisposed )
282 return;
283
284 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
285 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
286 // do not fire activation event multiple time for the same window
287 if( pWindow && (pWindow != mpActiveWindow) )
288 {
289 // if another window is active, fire deactivation event first
290 if( mpActiveWindow )
291 processWindowActivateEvent( mpActiveWindow, false );
292 // fire activation event for the new window
293 processWindowActivateEvent( pWindow, true );
294 mpActiveWindow = pWindow;
295 }
296}
297
298void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent )
299{
300 ::osl::MutexGuard aGuard( maMutex );
301
302 if( !mbDisposed )
303 {
304 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
305 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
306 // do not fire the deactivation event, if the window is not active (prevent multiple deactivation)
307 if( pWindow && (pWindow == mpActiveWindow) )
308 processWindowActivateEvent( pWindow, false );
309 // forget pointer to the active window
310 mpActiveWindow = nullptr;
311 }
312}
313
314void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent )
315{
316 ::osl::MutexGuard aGuard( maMutex );
317
318 mbWindowResized = true;
319 if( !mbDisposed && mbBorderChanged )
320 {
321 uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
322 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
323 }
324}
325
326void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ )
327{
328}
329
330void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ )
331{
332}
333
334void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ )
335{
336}
337
338void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ )
339{
340 ::osl::MutexGuard aGuard( maMutex );
341
342 mbBorderChanged = true;
343 if( !mbDisposed && mbWindowResized )
1
Assuming field 'mbDisposed' is false
2
Assuming field 'mbWindowResized' is true
3
Taking true branch
344 {
345 uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY );
346 uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController );
347 postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
4
Calling 'ScVbaEventListener::postWindowResizeEvent'
348 }
349}
350
351void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent )
352{
353 ::osl::MutexGuard aGuard( maMutex );
354
355 sal_Int32 nCount = rEvent.Changes.getLength();
356 if( mbDisposed || !mpDocShell || (nCount == 0) )
357 return;
358
359 util::ElementChange aChange = rEvent.Changes[ 0 ];
360 OUString sOperation;
361 aChange.Accessor >>= sOperation;
362 if( !sOperation.equalsIgnoreAsciiCase("cell-change") )
363 return;
364
365 if( nCount == 1 )
366 {
367 uno::Reference< table::XCellRange > xRangeObj;
368 aChange.ReplacedElement >>= xRangeObj;
369 if( xRangeObj.is() )
370 {
371 uno::Sequence< uno::Any > aArgs( 1 );
372 aArgs[0] <<= xRangeObj;
373 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
374 }
375 return;
376 }
377
378 ScRangeList aRangeList;
379 for( const util::ElementChange& rChange : rEvent.Changes )
380 {
381 rChange.Accessor >>= sOperation;
382 uno::Reference< table::XCellRange > xRangeObj;
383 rChange.ReplacedElement >>= xRangeObj;
384 if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") )
385 {
386 uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
387 if( xCellRangeAddressable.is() )
388 {
389 ScRange aRange;
390 ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
391 aRangeList.push_back( aRange );
392 }
393 }
394 }
395
396 if (!aRangeList.empty())
397 {
398 uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) );
399 uno::Sequence< uno::Any > aArgs(1);
400 aArgs[0] <<= xRanges;
401 mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
402 }
403}
404
405void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent )
406{
407 ::osl::MutexGuard aGuard( maMutex );
408
409 uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
410 if( xModel.is() )
411 {
412 OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" )do { if (true && (!(xModel.get() == mxModel.get()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx"
":" "412" ": "), "%s", "ScVbaEventListener::disposing - disposing from unknown model"
); } } while (false)
;
413 stopModelListening();
414 mbDisposed = true;
415 return;
416 }
417
418 uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY );
419 if( xController.is() )
420 {
421 stopControllerListening( xController );
422 return;
423 }
424}
425
426// private --------------------------------------------------------------------
427
428void ScVbaEventListener::startModelListening()
429{
430 try
431 {
432 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
433 xChangesNotifier->addChangesListener( this );
434 }
435 catch( uno::Exception& )
436 {
437 }
438}
439
440void ScVbaEventListener::stopModelListening()
441{
442 try
443 {
444 uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
445 xChangesNotifier->removeChangesListener( this );
446 }
447 catch( uno::Exception& )
448 {
449 }
450}
451
452uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const
453{
454 WindowControllerMap::const_iterator aIt = maControllers.find( pWindow );
455 return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second;
456}
457
458void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate )
459{
460 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
461 if( xController.is() )
462 {
463 uno::Sequence< uno::Any > aArgs( 1 );
464 aArgs[ 0 ] <<= xController;
465 mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs );
466 }
467}
468
469void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow )
470{
471 // check that the passed window is still alive (it must be registered in maControllers)
472 if( pWindow && (maControllers.count( pWindow ) > 0) )
5
Assuming 'pWindow' is non-null
6
Assuming the condition is true
7
Calling implicit destructor for 'VclPtr<vcl::Window>'
8
Calling '~Reference'
15
Returning from '~Reference'
16
Returning from destructor for 'VclPtr<vcl::Window>'
17
Taking true branch
473 {
474 mbWindowResized = mbBorderChanged = false;
475 acquire(); // ensure we don't get deleted before the timer fires
476 m_PostedWindows.insert(pWindow);
18
Use of memory after it is freed
477 Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent )::tools::detail::makeLink( ::tools::detail::castTo<ScVbaEventListener
*>(this), &ScVbaEventListener::LinkStubprocessWindowResizeEvent
)
, pWindow );
478 }
479}
480
481IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, void*, p, void )void ScVbaEventListener::LinkStubprocessWindowResizeEvent(void
* instance, void* data) { return static_cast<ScVbaEventListener
*>(instance)->processWindowResizeEvent(data); } void ScVbaEventListener
::processWindowResizeEvent(void* p)
482{
483 vcl::Window* pWindow = static_cast<vcl::Window*>(p);
484 ::osl::MutexGuard aGuard( maMutex );
485
486 /* Check that the passed window is still alive (it must be registered in
487 maControllers). While closing a document, postWindowResizeEvent() may
488 be called on the last window which posts a user event via
489 Application::PostUserEvent to call this event handler. VCL will trigger
490 the handler some time later. Sometimes, the window gets deleted before.
491 This is handled via the disposing() function which removes the window
492 pointer from the member maControllers. Thus, checking whether
493 maControllers contains pWindow ensures that the window is still alive. */
494 if( !mbDisposed && pWindow && !pWindow->IsDisposed() && (maControllers.count(pWindow) > 0) )
495 {
496 // do not fire event unless all mouse buttons have been released
497 vcl::Window::PointerState aPointerState = pWindow->GetPointerState();
498 if( (aPointerState.mnState & (MOUSE_LEFT(sal_uInt16(0x0001)) | MOUSE_MIDDLE(sal_uInt16(0x0002)) | MOUSE_RIGHT(sal_uInt16(0x0004)))) == 0 )
499 {
500 uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
501 if( xController.is() )
502 {
503 uno::Sequence< uno::Any > aArgs( 1 );
504 aArgs[ 0 ] <<= xController;
505 // #163419# do not throw exceptions into application core
506 mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs );
507 }
508 }
509 }
510 {
511 // note: there may be multiple processWindowResizeEvent outstanding
512 // for pWindow, so it may have been added to m_PostedWindows multiple
513 // times - so this must delete exactly one of these elements!
514 auto const iter(m_PostedWindows.find(pWindow));
515 assert(iter != m_PostedWindows.end())(static_cast <bool> (iter != m_PostedWindows.end()) ? void
(0) : __assert_fail ("iter != m_PostedWindows.end()", "/home/maarten/src/libreoffice/core/sc/source/ui/vba/vbaeventshelper.cxx"
, 515, __extension__ __PRETTY_FUNCTION__))
;
516 m_PostedWindows.erase(iter);
517 }
518 release();
519}
520
521ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs ) :
522 VbaEventsHelperBase( rArgs ),
523 mbOpened( false )
524{
525 mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class
526 mpDoc = mpDocShell ? &mpDocShell->GetDocument() : nullptr;
527
528 if( !mxModel.is() || !mpDocShell || !mpDoc )
529 return;
530
531 // global
532 auto registerAutoEvent = [this](sal_Int32 nID, const char* sName)
533 { registerEventHandler(nID, script::ModuleType::NORMAL, (OString("Auto_").concat(sName)).getStr(), -1, uno::Any(false)); };
534 registerAutoEvent(AUTO_OPEN, "Open");
535 registerAutoEvent(AUTO_CLOSE, "Close");
536
537 // Workbook
538 auto registerWorkbookEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex)
539 { registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Workbook_").concat(sName)).getStr(), nCancelIndex, uno::Any(false)); };
540 registerWorkbookEvent( WORKBOOK_ACTIVATE, "Activate", -1 );
541 registerWorkbookEvent( WORKBOOK_DEACTIVATE, "Deactivate", -1 );
542 registerWorkbookEvent( WORKBOOK_OPEN, "Open", -1 );
543 registerWorkbookEvent( WORKBOOK_BEFORECLOSE, "BeforeClose", 0 );
544 registerWorkbookEvent( WORKBOOK_BEFOREPRINT, "BeforePrint", 0 );
545 registerWorkbookEvent( WORKBOOK_BEFORESAVE, "BeforeSave", 1 );
546 registerWorkbookEvent( WORKBOOK_AFTERSAVE, "AfterSave", -1 );
547 registerWorkbookEvent( WORKBOOK_NEWSHEET, "NewSheet", -1 );
548 registerWorkbookEvent( WORKBOOK_WINDOWACTIVATE, "WindowActivate", -1 );
549 registerWorkbookEvent( WORKBOOK_WINDOWDEACTIVATE, "WindowDeactivate", -1 );
550 registerWorkbookEvent( WORKBOOK_WINDOWRESIZE, "WindowResize", -1 );
551
552 // Worksheet events. All events have a corresponding workbook event.
553 auto registerWorksheetEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex)
554 {
555 registerEventHandler(nID, script::ModuleType::DOCUMENT, (OString("Worksheet_").concat(sName)).getStr(),
556 nCancelIndex, uno::Any(true));
557 registerEventHandler(USERDEFINED_START + nID, script::ModuleType::DOCUMENT,
558 (OString("Workbook_Worksheet").concat(sName)).getStr(),
559 ((nCancelIndex >= 0) ? (nCancelIndex + 1) : -1), uno::Any(false));
560 };
561 registerWorksheetEvent( WORKSHEET_ACTIVATE, "Activate", -1 );
562 registerWorksheetEvent( WORKSHEET_DEACTIVATE, "Deactivate", -1 );
563 registerWorksheetEvent( WORKSHEET_BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 );
564 registerWorksheetEvent( WORKSHEET_BEFORERIGHTCLICK, "BeforeRightClick", 1 );
565 registerWorksheetEvent( WORKSHEET_CALCULATE, "Calculate", -1 );
566 registerWorksheetEvent( WORKSHEET_CHANGE, "Change", -1 );
567 registerWorksheetEvent( WORKSHEET_SELECTIONCHANGE, "SelectionChange", -1 );
568 registerWorksheetEvent( WORKSHEET_FOLLOWHYPERLINK, "FollowHyperlink", -1 );
569}
570
571ScVbaEventsHelper::~ScVbaEventsHelper()
572{
573}
574
575void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent )
576{
577 static const uno::Sequence< uno::Any > saEmptyArgs;
578 if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) ||
579 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add
580 {
581 processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs );
582 }
583 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) )
584 {
585 processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs );
586 }
587 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) )
588 {
589 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
590 }
591 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) ||
592 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) ||
593 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) )
594 {
595 uno::Sequence< uno::Any > aArgs( 1 );
596 aArgs[ 0 ] <<= true;
597 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
598 }
599 else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) ||
600 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) ||
601 (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) )
602 {
603 uno::Sequence< uno::Any > aArgs( 1 );
604 aArgs[ 0 ] <<= false;
605 processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
606 }
607 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
608 {
609 /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE
610 events and stop listening to the model (done in base class). */
611 uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
612 if( xController.is() )
613 {
614 uno::Sequence< uno::Any > aArgs( 1 );
615 aArgs[ 0 ] <<= xController;
616 processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs );
617 }
618 processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
619 }
620 else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) )
621 {
622 uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
623 if( mxListener && xController.is() )
624 mxListener->startControllerListening( xController );
625 }
626 VbaEventsHelperBase::notifyEvent( rEvent );
627}
628
629OUString ScVbaEventsHelper::getImplementationName()
630{
631 return "ScVbaEventsHelper";
632}
633
634css::uno::Sequence<OUString> ScVbaEventsHelper::getSupportedServiceNames()
635{
636 return css::uno::Sequence<OUString>{
637 "com.sun.star.script.vba.VBASpreadsheetEventProcessor"};
638}
639
640// protected ------------------------------------------------------------------
641
642bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue,
643 const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs )
644{
645 // document and document shell are needed during event processing
646 if( !mpShell || !mpDoc )
647 throw uno::RuntimeException();
648
649 /* For document events: check if events are enabled via the
650 Application.EnableEvents symbol (this is an Excel-only attribute).
651 Check this again for every event, as the event handler may change the
652 state of the EnableEvents symbol. Global events such as AUTO_OPEN and
653 AUTO_CLOSE are always enabled. */
654 bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled();
655
656 // framework and Calc fire a few events before 'OnLoad', ignore them
657 if( bExecuteEvent )
658 bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened;
659
660 // special handling for some events
661 if( bExecuteEvent ) switch( rInfo.mnEventId )
662 {
663 case WORKBOOK_OPEN:
664 {
665 // execute delayed Activate event too (see above)
666 rEventQueue.emplace_back(WORKBOOK_ACTIVATE );
667 uno::Sequence< uno::Any > aArgs( 1 );
668 aArgs[ 0 ] <<= mxModel->getCurrentController();
669 rEventQueue.emplace_back( WORKBOOK_WINDOWACTIVATE, aArgs );
670 rEventQueue.emplace_back(AUTO_OPEN );
671 // remember initial selection
672 maOldSelection <<= mxModel->getCurrentSelection();
673 }
674 break;
675 case WORKSHEET_SELECTIONCHANGE:
676 // if selection is not changed, then do not fire the event
677 bExecuteEvent = isSelectionChanged( rArgs, 0 );
678 break;
679 }
680
681 if( bExecuteEvent )
682 {
683 // add workbook event associated to a sheet event
684 bool bSheetEvent = false;
685 if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent )
686 rEventQueue.emplace_back( rInfo.mnEventId + USERDEFINED_START, rArgs );
687 }
688
689 return bExecuteEvent;
690}
691
692uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo,
693 const uno::Sequence< uno::Any >& rArgs )
694{
695 // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below
696 bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START;
697 sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId;
698
699 uno::Sequence< uno::Any > aVbaArgs;
700 switch( nEventId )
701 {
702 // *** Workbook ***
703
704 // no arguments
705 case WORKBOOK_ACTIVATE:
706 case WORKBOOK_DEACTIVATE:
707 case WORKBOOK_OPEN:
708 break;
709 // 1 arg: cancel
710 case WORKBOOK_BEFORECLOSE:
711 case WORKBOOK_BEFOREPRINT:
712 aVbaArgs.realloc( 1 );
713 // current cancel state will be inserted by caller
714 break;
715 // 2 args: saveAs, cancel
716 case WORKBOOK_BEFORESAVE:
717 aVbaArgs.realloc( 2 );
718 checkArgumentType< bool >( rArgs, 0 );
719 aVbaArgs[ 0 ] = rArgs[ 0 ];
720 // current cancel state will be inserted by caller
721 break;
722 // 1 arg: success
723 case WORKBOOK_AFTERSAVE:
724 aVbaArgs.realloc( 1 );
725 checkArgumentType< bool >( rArgs, 0 );
726 aVbaArgs[ 0 ] = rArgs[ 0 ];
727 break;
728 // 1 arg: window
729 case WORKBOOK_WINDOWACTIVATE:
730 case WORKBOOK_WINDOWDEACTIVATE:
731 case WORKBOOK_WINDOWRESIZE:
732 aVbaArgs.realloc( 1 );
733 aVbaArgs[ 0 ] = createWindow( rArgs, 0 );
734 break;
735 // 1 arg: worksheet
736 case WORKBOOK_NEWSHEET:
737 aVbaArgs.realloc( 1 );
738 aVbaArgs[ 0 ] = createWorksheet( rArgs, 0 );
739 break;
740
741 // *** Worksheet ***
742
743 // no arguments
744 case WORKSHEET_ACTIVATE:
745 case WORKSHEET_CALCULATE:
746 case WORKSHEET_DEACTIVATE:
747 break;
748 // 1 arg: range
749 case WORKSHEET_CHANGE:
750 case WORKSHEET_SELECTIONCHANGE:
751 aVbaArgs.realloc( 1 );
752 aVbaArgs[ 0 ] = createRange( rArgs, 0 );
753 break;
754 // 2 args: range, cancel
755 case WORKSHEET_BEFOREDOUBLECLICK:
756 case WORKSHEET_BEFORERIGHTCLICK:
757 aVbaArgs.realloc( 2 );
758 aVbaArgs[ 0 ] = createRange( rArgs, 0 );
759 // current cancel state will be inserted by caller
760 break;
761 // 1 arg: hyperlink
762 case WORKSHEET_FOLLOWHYPERLINK:
763 aVbaArgs.realloc( 1 );
764 aVbaArgs[ 0 ] = createHyperlink( rArgs, 0 );
765 break;
766 }
767
768 /* For workbook events associated to sheet events, the workbook event gets
769 the same arguments but with a Worksheet object in front of them. */
770 if( bSheetEventAsBookEvent )
771 {
772 sal_Int32 nLength = aVbaArgs.getLength();
773 uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 );
774 aVbaArgs2[ 0 ] = createWorksheet( rArgs, 0 );
775 std::copy_n(aVbaArgs.begin(), nLength, std::next(aVbaArgs2.begin()));
776 aVbaArgs = aVbaArgs2;
777 }
778
779 return aVbaArgs;
780}
781
782void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue,
783 const EventHandlerInfo& rInfo, bool bCancel )
784{
785 switch( rInfo.mnEventId )
786 {
787 case WORKBOOK_OPEN:
788 mbOpened = true;
789 // register the listeners
790 if( !mxListener.is() )
791 mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell );
792 break;
793 case WORKBOOK_BEFORECLOSE:
794 /* Execute Auto_Close only if not cancelled by event handler, but
795 before UI asks user whether to cancel closing the document. */
796 if( !bCancel )
797 rEventQueue.emplace_back(AUTO_CLOSE );
798 break;
799 }
800}
801
802OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo,
803 const uno::Sequence< uno::Any >& rArgs ) const
804{
805 bool bSheetEvent = false;
806 rInfo.maUserData >>= bSheetEvent;
807 SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1;
808 if( bSheetEvent && (nTab < 0) )
809 throw lang::IllegalArgumentException();
810
811 OUString aCodeName;
812 if( bSheetEvent )
813 mpDoc->GetCodeName( nTab, aCodeName );
814 else
815 aCodeName = mpDoc->GetCodeName();
816 return aCodeName;
817}
818
819// private --------------------------------------------------------------------
820
821namespace {
822
823/** Compares the passed range lists representing sheet selections. Ignores
824 selections that refer to different sheets (returns false in this case). */
825bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight )
826{
827 // one of the range lists empty? -> return false, if both lists empty
828 bool bLeftEmpty = rLeft.empty();
829 bool bRightEmpty = rRight.empty();
830 if( bLeftEmpty || bRightEmpty )
831 return !(bLeftEmpty && bRightEmpty);
832
833 // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet)
834 if (rLeft[0].aStart.Tab() != rRight[0].aStart.Tab())
835 return false;
836
837 // compare all ranges
838 return rLeft != rRight;
839}
840
841} // namespace
842
843bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex )
844{
845 uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY );
846 uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false );
847 ScCellRangesBase* pOldCellRanges = comphelper::getUnoTunnelImplementation<ScCellRangesBase>( xOldSelection );
848 ScCellRangesBase* pNewCellRanges = comphelper::getUnoTunnelImplementation<ScCellRangesBase>( xNewSelection );
849 bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() );
850 maOldSelection <<= xNewSelection;
851 return bChanged;
852}
853
854uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
855{
856 // extract sheet index, will throw, if parameter is invalid
857 SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex );
858 return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) );
859}
860
861uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
862{
863 // it is possible to pass an existing VBA Range object
864 uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
865 if( !xVbaRange.is() )
866 {
867 uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
868 uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex );
869 if ( !xRanges.is() && !xRange.is() )
870 throw lang::IllegalArgumentException();
871
872 uno::Sequence< uno::Any > aArgs( 2 );
873 if ( xRanges.is() )
874 {
875 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRanges );
876 aArgs[ 1 ] <<= xRanges;
877 }
878 else
879 {
880 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xRange );
881 aArgs[ 1 ] <<= xRange;
882 }
883 xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW );
884 }
885 return uno::Any( xVbaRange );
886}
887
888uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
889{
890 uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false );
891 uno::Sequence< uno::Any > aArgs( 2 );
892 aArgs[ 0 ] <<= excel::getUnoSheetModuleObj( xCell );
893 aArgs[ 1 ] <<= xCell;
894 uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW );
895 return uno::Any( xHyperlink );
896}
897
898uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
899{
900 uno::Sequence< uno::Any > aArgs( 3 );
901 aArgs[ 0 ] <<= getVBADocument( mxModel );
902 aArgs[ 1 ] <<= mxModel;
903 aArgs[ 2 ] <<= getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false );
904 uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW );
905 return uno::Any( xWindow );
906}
907
908extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) css::uno::XInterface *
909ScVbaEventsHelper_get_implementation(
910 css::uno::XComponentContext * /*context*/,
911 css::uno::Sequence<css::uno::Any> const &arguments)
912{
913 return cppu::acquire(new ScVbaEventsHelper(arguments));
914}
915
916/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
)
9
Taking true branch
113 m_pBody->release();
10
Calling 'VclReferenceBase::release'
14
Returning; memory was released
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
11
Assuming the condition is true
12
Taking true branch
40 delete this;
13
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif