sal_Bool SAL_CALL VbaEventsHelperBase::processVbaEvent( sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs )
{ /* Derived classes may add new event identifiers to be processed while processingtheoriginalevent.Allunprocessedeventsarecollectedin
a queue. First element in the queue is the next event to be processed. */
EventQueue aEventQueue;
aEventQueue.emplace_back( nEventId, rArgs );
/* bCancel will contain the current Cancel value. It is possible that multipleeventswilltrytomodifytheCancelvalue.Everyevent
handler receives the Cancel value of the previous event handler. */ bool bCancel = false;
/* bExecuted will change to true if at least one event handler has been
found and executed. */ bool bExecuted = false;
/* Loop as long as there are more events to be processed. Derived classes mayaddneweventstobeprocessedinthevirtualimplPrepareEvent()
function. */ while( !aEventQueue.empty() )
{ /* Check that all class members are available, and that we are not disposed(thismayhavehappenedatanytimeduringexecutionof
the last event handler). */ if( mbDisposed || !mxModel.is() || !mpShell ) throw uno::RuntimeException();
// get info for next event const EventHandlerInfo& rInfo = getEventHandlerInfo( aEventQueue.front().mnEventId );
uno::Sequence< uno::Any > aEventArgs = aEventQueue.front().maArgs;
aEventQueue.pop_front();
SAL_INFO("vbahelper", "VbaEventsHelperBase::processVbaEvent( \"" << rInfo.maMacroName << "\" )");
/* Let derived classes prepare the event, they may add new events for nextiteration.Iffalseisreturned,theeventhandlermustnotbe
called. */ if( implPrepareEvent( aEventQueue, rInfo, aEventArgs ) )
{ // search the event handler macro in the document
OUString aMacroPath = getEventHandlerPath( rInfo, aEventArgs ); if( !aMacroPath.isEmpty() )
{ // build the argument list
uno::Sequence< uno::Any > aVbaArgs = implBuildArgumentList( rInfo, aEventArgs ); // insert current cancel value if( rInfo.mnCancelIndex >= 0 )
{ if( rInfo.mnCancelIndex >= aVbaArgs.getLength() ) throw lang::IllegalArgumentException();
aVbaArgs.getArray()[ rInfo.mnCancelIndex ] <<= bCancel;
} // execute the event handler
uno::Any aRet, aCaller;
executeMacro( mpShell, aMacroPath, aVbaArgs, aRet, aCaller ); // extract new cancel value (may be boolean or any integer type) if( rInfo.mnCancelIndex >= 0 )
{
checkArgument( aVbaArgs, rInfo.mnCancelIndex );
bCancel = extractBoolFromAny( aVbaArgs[ rInfo.mnCancelIndex ] );
} // event handler has been found
bExecuted = true;
}
} // post processing (also, if event handler does not exist, or disabled, or on error
implPostProcessEvent( aEventQueue, rInfo, bCancel );
}
// if event handlers want to cancel the event, do so regardless of any errors if( bCancel ) throw util::VetoException();
// return true, if at least one event handler has been found return bExecuted;
}
// check that the sender of the event is the VBA library
uno::Reference< script::vba::XVBAModuleInfo > xSender( rEvent.Base, uno::UNO_QUERY ); if( mxModuleInfos.get() != xSender.get() ) return;
// process all changed modules for( const util::ElementChange& rChange : rEvent.Changes )
{
OUString aModuleName; if( (rChange.Accessor >>= aModuleName) && !aModuleName.isEmpty() ) try
{ // invalidate event handler path map depending on module type if( getModuleType( aModuleName ) == script::ModuleType::NORMAL ) // paths to global event handlers are stored with empty key (will be searched in all normal code modules)
maEventPaths.erase( OUString() ); else // paths to class/form/document event handlers are keyed by module name
maEventPaths.erase( aModuleName );
} catch( uno::Exception& )
{
}
}
}
sal_Bool SAL_CALL VbaEventsHelperBase::hasVbaEventHandler( sal_Int32 nEventId, const uno::Sequence< uno::Any >& rArgs )
{
EventHandlerInfoMap::const_iterator aIt = maEventInfos.find( nEventId ); if( aIt == maEventInfos.end() ) returnfalse; // throwing a lot of exceptions is slow. else// getEventHandlerPath() searches for the macro in the document return !getEventHandlerPath( aIt->second, rArgs ).isEmpty();
}
OUString VbaEventsHelperBase::getEventHandlerPath( const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs )
{
OUString aModuleName; switch( rInfo.mnModuleType )
{ // global event handlers may exist in any standard code module case script::ModuleType::NORMAL: break;
// document event: get name of the code module associated to the event sender case script::ModuleType::DOCUMENT:
aModuleName = implGetDocumentModuleName( rInfo, rArgs ); if( aModuleName.isEmpty() ) throw lang::IllegalArgumentException(); break;
default: throw uno::RuntimeException(u"This module type is unsupported"_ustr); // unsupported module type
}
/* Performance improvement: Check the list of existing event handlers
instead of searching in Basic source code every time. */
EventHandlerPathMap::iterator aIt = maEventPaths.find( aModuleName );
ModulePathMap& rPathMap = (aIt == maEventPaths.end()) ? updateModulePathMap( aModuleName ) : aIt->second; return rPathMap[ rInfo.mnEventId ];
}
sal_Int32 VbaEventsHelperBase::getModuleType( const OUString& rModuleName )
{ // make sure the VBA library exists
ensureVBALibrary();
// no module specified: global event handler in standard code modules if( rModuleName.isEmpty() ) return script::ModuleType::NORMAL;
// get module type from module info try
{ return mxModuleInfos->getModuleInfo( rModuleName ).ModuleType;
} catch( uno::Exception& )
{
} throw uno::RuntimeException();
}
VbaEventsHelperBase::ModulePathMap& VbaEventsHelperBase::updateModulePathMap( const OUString& rModuleName )
{ // get type of the specified module (throws on error)
sal_Int32 nModuleType = getModuleType( rModuleName ); // search for all event handlers
ModulePathMap& rPathMap = maEventPaths[ rModuleName ];
// Use WORKBOOK_OPEN as a way to get the codename for ThisWorkbook
OUString sThisWorkbook; if (getImplementationName() == "ScVbaEventsHelper")
{
EventHandlerInfo& rThisWorksheetInfo
= maEventInfos[css::script::vba::VBAEventId::WORKBOOK_OPEN];
css::uno::Sequence<css::uno::Any> aNoArgs;
sThisWorkbook = implGetDocumentModuleName(rThisWorksheetInfo, aNoArgs);
}
// Use DOCUMENT_OPEN as a way to get the codename for ThisDocument
OUString sThisDocument; if (getImplementationName() == "SwVbaEventsHelper")
{
EventHandlerInfo& rThisDocumentInfo
= maEventInfos[css::script::vba::VBAEventId::DOCUMENT_OPEN];
css::uno::Sequence<css::uno::Any> aNoArgs;
sThisDocument = implGetDocumentModuleName(rThisDocumentInfo, aNoArgs);
}
for( constauto& rEventInfo : maEventInfos )
{ const EventHandlerInfo& rInfo = rEventInfo.second; if( rInfo.mnModuleType == nModuleType )
{
OUString sName; bool bOnlyPublic = false;
OUString sSkipModule; if (rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_NEW
|| rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_OPEN
|| rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_CLOSE)
{ if (getImplementationName() == "ScVbaEventsHelper")
{ // Only in Calc, ignore Auto_* in ThisWorkbook
sSkipModule = sThisWorkbook;
} elseif (getImplementationName() == "SwVbaEventsHelper")
{ // Only in Word, Auto* only runs if defined as Public, not Private.
bOnlyPublic = true; // Only in Word, auto* subroutines in ThisDocument have highest priority
sName = resolveVBAMacro(mpShell, maLibraryName, sThisDocument,
rInfo.maMacroName, bOnlyPublic, sSkipModule);
}
}
if (sName.isEmpty())
sName = resolveVBAMacro(mpShell, maLibraryName, rModuleName,
rInfo.maMacroName, bOnlyPublic, sSkipModule);
// Only in Word (with lowest priority), an Auto* module can execute a "Public Sub Main" if (sName.isEmpty() && rModuleName.isEmpty()
&& getImplementationName() == "SwVbaEventsHelper")
{ if (rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_NEW
|| rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_OPEN
|| rInfo.mnEventId == css::script::vba::VBAEventId::AUTO_CLOSE)
{
sName = resolveVBAMacro(mpShell, maLibraryName, rInfo.maMacroName, u"Main"_ustr,
bOnlyPublic, sSkipModule);
}
}
rPathMap[rInfo.mnEventId] = sName;
}
} return rPathMap;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.