/* -*- 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 .
*/
// if the GraphicHelper tries to use noStorage it will of course crash // but... this shouldn't happen as there is no reason for GraphicHelper // to do that when importing VBA projects
GraphicHelper grfHlp(mxContext, xFrame, StorageRef());
importVbaProject( rVbaPrjStrg, grfHlp ); // return true if something has been imported return (mxBasicLib.is() && mxBasicLib->hasElements()) ||
(mxDialogLib.is() && mxDialogLib->hasElements());
}
void VbaProject::importVbaProject( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper )
{ if( rVbaPrjStrg.isStorage() )
{ // load the code modules and forms if( isImportVba() )
importVba( rVbaPrjStrg, rGraphicHelper ); // copy entire storage into model if( isExportVba() )
copyStorage( rVbaPrjStrg );
}
}
/* Read the 'VBA/dir' stream which contains general settings of the VBA project such as the text encoding used throughout several streams, and a list of all code modules.
*/
BinaryXInputStream aInStrm( xVbaStrg->openInputStream( u"dir"_ustr ), true ); // VbaInputStream implements decompression
VbaInputStream aDirStrm( aInStrm );
OSL_ENSURE( !aDirStrm.isEof(), "VbaProject::importVba - cannot open 'dir' stream" ); if( aDirStrm.isEof() ) return;
// virtual call, derived classes may do some preparations
prepareImport();
// read all records of the directory
rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252;
sal_uInt16 nModuleCount = 0; bool bExecutable = isImportVbaExecutable();
/* The directory does not contain the real type of the modules, it distinguishes only between 'procedural' and 'document' (the latter includes class and form modules). Now, the exact type of all modules will be read from the 'PROJECT' stream. It consists of text lines in 'key=value' format which list the code modules by type.
- The line 'document=<modulename>/&HXXXXXXXX' declares document modules. These are attached to the Word document (usually called 'ThisDocument'), the Excel workbook (usually called 'ThisWorkbook'), or single Excel worksheets or chartsheets (usually called 'SheetX' or 'ChartX', X being a decimal number). Of course, users may rename all these modules. The slash character separates an automation server version number (hexadecimal 'XXXXXXXX') from the module name. - The line 'Module=<modulename>' declares common procedural code modules. - The line 'Class=<modulename>' declares a class module. - The line 'BaseClass=<modulename>' declares a code module attached to a user form with the same name.
*/
BinaryXInputStream aPrjStrm( rVbaPrjStrg.openInputStream( u"PROJECT"_ustr ), true );
OSL_ENSURE( !aPrjStrm.isEof(), "VbaProject::importVba - cannot open 'PROJECT' stream" ); // do not exit if this stream does not exist, but proceed to load the modules below if( !aPrjStrm.isEof() )
{
TextInputStream aPrjTextStrm( mxContext, aPrjStrm, eTextEnc );
OUString aKey, aValue; bool bExitLoop = false; while( !bExitLoop && !aPrjTextStrm.isEof() )
{ // read a text line from the stream
OUString aLine = aPrjTextStrm.readLine().trim();
sal_Int32 nLineLen = aLine.getLength(); // exit if a subsection starts (section name is given in brackets)
bExitLoop = (nLineLen >= 2) && (aLine[ 0 ] == '[') && (aLine[ nLineLen - 1 ] == ']'); if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) )
{
sal_Int32 nType = ModuleType::UNKNOWN; if( aKey.equalsIgnoreAsciiCase( "Document" ) )
{
nType = ModuleType::DOCUMENT; // strip automation server version from module names
sal_Int32 nSlashPos = aValue.indexOf( '/' ); if( nSlashPos >= 0 )
aValue = aValue.copy( 0, nSlashPos );
} elseif( aKey.equalsIgnoreAsciiCase( "Module" ) )
nType = ModuleType::NORMAL; elseif( aKey.equalsIgnoreAsciiCase( "Class" ) )
nType = ModuleType::CLASS; elseif( aKey.equalsIgnoreAsciiCase( "BaseClass" ) )
nType = ModuleType::FORM;
try
{ /* Set library container to VBA compatibility mode. This will create the VBA Globals object and store it in the Basic manager of the
document. */ try
{
Reference< XVBACompatibility > xVBACompat( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW );
xVBACompat->setVBACompatibilityMode( true );
xVBACompat->setProjectName( maPrjName );
/* Now it is time to load the source code. All modules will be inserted into the Basic library of the document specified by the 'maPrjName' member. Do not create the Basic library, if there are no modules
specified. */ if( !maModules.empty() || !aDummyModules.empty() ) try
{ // get the model factory and the basic library
Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW );
Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW );
// try to get access to document objects related to code modules
Reference< XNameAccess > xDocObjectNA; try
{
xDocObjectNA.set( xModelFactory->createInstance( u"ooo.vba.VBAObjectModuleObjectProvider"_ustr ), UNO_QUERY );
} catch(const Exception& )
{ // not all documents support this
}
if( xBasicLib.is() )
{ // #TODO cater for mxOleOverridesSink, like I used to before // call Basic source code import for each module, std::[c]ref enforces pass-by-ref
maModules.forEachMem( &VbaModule::createAndImportModule,
::std::ref( *xVbaStrg ), ::std::cref( xBasicLib ),
::std::cref( xDocObjectNA ) );
/* Load the forms. The file format specification requires that a module must exist for every form. We are a bit more tolerant and scan the project storage for all form substorages. This may 'repair' broken VBA
storages that misses to mention a module for an existing form. */
::std::vector< OUString > aElements;
rVbaPrjStrg.getElementNames( aElements ); for (autoconst& elem : aElements)
{ // try to open the element as storage if( elem != "VBA" )
{
StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( elem, false ); if( xSubStrg ) try
{ // resolve module name from storage name (which equals the module stream name)
VbaModule* pModule = maModulesByStrm.get( elem ).get();
OSL_ENSURE( pModule && (pModule->getType() == ModuleType::FORM), "VbaProject::importVba - form substorage without form module" );
OUString aModuleName; if( pModule )
aModuleName = pModule->getName();
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.