1*ca5ec200SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*ca5ec200SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*ca5ec200SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*ca5ec200SAndrew Rist * distributed with this work for additional information 6*ca5ec200SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*ca5ec200SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*ca5ec200SAndrew Rist * "License"); you may not use this file except in compliance 9*ca5ec200SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*ca5ec200SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*ca5ec200SAndrew Rist * software distributed under the License is distributed on an 15*ca5ec200SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*ca5ec200SAndrew Rist * KIND, either express or implied. See the License for the 17*ca5ec200SAndrew Rist * specific language governing permissions and limitations 18*ca5ec200SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*ca5ec200SAndrew Rist *************************************************************/ 21*ca5ec200SAndrew Rist 22*ca5ec200SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "oox/ole/vbaproject.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include <com/sun/star/document/XStorageBasedDocument.hpp> 27cdf0e10cSrcweir #include <com/sun/star/embed/ElementModes.hpp> 28cdf0e10cSrcweir #include <com/sun/star/embed/XTransactedObject.hpp> 29cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp> 30cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 31cdf0e10cSrcweir #include <com/sun/star/script/ModuleType.hpp> 32cdf0e10cSrcweir #include <com/sun/star/script/XLibraryContainer.hpp> 33cdf0e10cSrcweir #include <com/sun/star/script/vba/XVBACompatibility.hpp> 34cdf0e10cSrcweir #include <com/sun/star/script/vba/XVBAMacroResolver.hpp> 35cdf0e10cSrcweir #include <com/sun/star/uno/XComponentContext.hpp> 36cdf0e10cSrcweir #include <comphelper/configurationhelper.hxx> 37cdf0e10cSrcweir #include <comphelper/string.hxx> 38cdf0e10cSrcweir #include <rtl/tencinfo.h> 39cdf0e10cSrcweir #include <rtl/ustrbuf.h> 40cdf0e10cSrcweir #include "oox/helper/binaryinputstream.hxx" 41cdf0e10cSrcweir #include "oox/helper/containerhelper.hxx" 42cdf0e10cSrcweir #include "oox/helper/propertyset.hxx" 43cdf0e10cSrcweir #include "oox/helper/textinputstream.hxx" 44cdf0e10cSrcweir #include "oox/ole/olestorage.hxx" 45cdf0e10cSrcweir #include "oox/ole/vbacontrol.hxx" 46cdf0e10cSrcweir #include "oox/ole/vbahelper.hxx" 47cdf0e10cSrcweir #include "oox/ole/vbainputstream.hxx" 48cdf0e10cSrcweir #include "oox/ole/vbamodule.hxx" 49cdf0e10cSrcweir 50cdf0e10cSrcweir namespace oox { 51cdf0e10cSrcweir namespace ole { 52cdf0e10cSrcweir 53cdf0e10cSrcweir // ============================================================================ 54cdf0e10cSrcweir 55cdf0e10cSrcweir using namespace ::com::sun::star::container; 56cdf0e10cSrcweir using namespace ::com::sun::star::document; 57cdf0e10cSrcweir using namespace ::com::sun::star::embed; 58cdf0e10cSrcweir using namespace ::com::sun::star::frame; 59cdf0e10cSrcweir using namespace ::com::sun::star::io; 60cdf0e10cSrcweir using namespace ::com::sun::star::lang; 61cdf0e10cSrcweir using namespace ::com::sun::star::script; 62cdf0e10cSrcweir using namespace ::com::sun::star::script::vba; 63cdf0e10cSrcweir using namespace ::com::sun::star::uno; 64cdf0e10cSrcweir 65cdf0e10cSrcweir using ::comphelper::ConfigurationHelper; 66cdf0e10cSrcweir using ::rtl::OUString; 67cdf0e10cSrcweir using ::rtl::OUStringBuffer; 68cdf0e10cSrcweir 69cdf0e10cSrcweir // ============================================================================ 70cdf0e10cSrcweir 71cdf0e10cSrcweir namespace { 72cdf0e10cSrcweir 73cdf0e10cSrcweir bool lclReadConfigItem( const Reference< XInterface >& rxConfigAccess, const OUString& rItemName ) 74cdf0e10cSrcweir { 75cdf0e10cSrcweir // some applications do not support all configuration items, assume 'false' in this case 76cdf0e10cSrcweir try 77cdf0e10cSrcweir { 78cdf0e10cSrcweir Any aItem = ConfigurationHelper::readRelativeKey( rxConfigAccess, CREATE_OUSTRING( "Filter/Import/VBA" ), rItemName ); 79cdf0e10cSrcweir return aItem.has< bool >() && aItem.get< bool >(); 80cdf0e10cSrcweir } 81cdf0e10cSrcweir catch( Exception& ) 82cdf0e10cSrcweir { 83cdf0e10cSrcweir } 84cdf0e10cSrcweir return false; 85cdf0e10cSrcweir } 86cdf0e10cSrcweir 87cdf0e10cSrcweir } // namespace 88cdf0e10cSrcweir 89cdf0e10cSrcweir // ---------------------------------------------------------------------------- 90cdf0e10cSrcweir 91cdf0e10cSrcweir VbaFilterConfig::VbaFilterConfig( const Reference< XComponentContext >& rxContext, const OUString& rConfigCompName ) 92cdf0e10cSrcweir { 93cdf0e10cSrcweir OSL_ENSURE( rxContext.is(), "VbaFilterConfig::VbaFilterConfig - missing component context" ); 94cdf0e10cSrcweir if( rxContext.is() ) try 95cdf0e10cSrcweir { 96cdf0e10cSrcweir OSL_ENSURE( rConfigCompName.getLength() > 0, "VbaFilterConfig::VbaFilterConfig - invalid configuration component name" ); 97cdf0e10cSrcweir OUString aConfigPackage = CREATE_OUSTRING( "org.openoffice.Office." ) + rConfigCompName; 98cdf0e10cSrcweir Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW ); 99cdf0e10cSrcweir mxConfigAccess = ConfigurationHelper::openConfig( xFactory, aConfigPackage, ConfigurationHelper::E_READONLY ); 100cdf0e10cSrcweir } 101cdf0e10cSrcweir catch( Exception& ) 102cdf0e10cSrcweir { 103cdf0e10cSrcweir } 104cdf0e10cSrcweir OSL_ENSURE( mxConfigAccess.is(), "VbaFilterConfig::VbaFilterConfig - cannot open configuration" ); 105cdf0e10cSrcweir } 106cdf0e10cSrcweir 107cdf0e10cSrcweir VbaFilterConfig::~VbaFilterConfig() 108cdf0e10cSrcweir { 109cdf0e10cSrcweir } 110cdf0e10cSrcweir 111cdf0e10cSrcweir bool VbaFilterConfig::isImportVba() const 112cdf0e10cSrcweir { 113cdf0e10cSrcweir return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Load" ) ); 114cdf0e10cSrcweir } 115cdf0e10cSrcweir 116cdf0e10cSrcweir bool VbaFilterConfig::isImportVbaExecutable() const 117cdf0e10cSrcweir { 118cdf0e10cSrcweir return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Executable" ) ); 119cdf0e10cSrcweir } 120cdf0e10cSrcweir 121cdf0e10cSrcweir bool VbaFilterConfig::isExportVba() const 122cdf0e10cSrcweir { 123cdf0e10cSrcweir return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Save" ) ); 124cdf0e10cSrcweir } 125cdf0e10cSrcweir 126cdf0e10cSrcweir // ============================================================================ 127cdf0e10cSrcweir 128cdf0e10cSrcweir VbaMacroAttacherBase::VbaMacroAttacherBase( const OUString& rMacroName ) : 129cdf0e10cSrcweir maMacroName( rMacroName ) 130cdf0e10cSrcweir { 131cdf0e10cSrcweir OSL_ENSURE( maMacroName.getLength() > 0, "VbaMacroAttacherBase::VbaMacroAttacherBase - empty macro name" ); 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir VbaMacroAttacherBase::~VbaMacroAttacherBase() 135cdf0e10cSrcweir { 136cdf0e10cSrcweir } 137cdf0e10cSrcweir 138cdf0e10cSrcweir void VbaMacroAttacherBase::resolveAndAttachMacro( const Reference< XVBAMacroResolver >& rxResolver ) 139cdf0e10cSrcweir { 140cdf0e10cSrcweir try 141cdf0e10cSrcweir { 142cdf0e10cSrcweir attachMacro( rxResolver->resolveVBAMacroToScriptURL( maMacroName ) ); 143cdf0e10cSrcweir } 144cdf0e10cSrcweir catch( Exception& ) 145cdf0e10cSrcweir { 146cdf0e10cSrcweir } 147cdf0e10cSrcweir } 148cdf0e10cSrcweir 149cdf0e10cSrcweir // ============================================================================ 150cdf0e10cSrcweir 151cdf0e10cSrcweir VbaProject::VbaProject( const Reference< XComponentContext >& rxContext, 152cdf0e10cSrcweir const Reference< XModel >& rxDocModel, const OUString& rConfigCompName ) : 153cdf0e10cSrcweir VbaFilterConfig( rxContext, rConfigCompName ), 154cdf0e10cSrcweir mxContext( rxContext ), 155cdf0e10cSrcweir mxDocModel( rxDocModel ), 156cdf0e10cSrcweir maPrjName( CREATE_OUSTRING( "Standard" ) ) 157cdf0e10cSrcweir { 158cdf0e10cSrcweir OSL_ENSURE( mxContext.is(), "VbaProject::VbaProject - missing component context" ); 159cdf0e10cSrcweir OSL_ENSURE( mxDocModel.is(), "VbaProject::VbaProject - missing document model" ); 160cdf0e10cSrcweir mxBasicLib = openLibrary( PROP_BasicLibraries, false ); 161cdf0e10cSrcweir mxDialogLib = openLibrary( PROP_DialogLibraries, false ); 162cdf0e10cSrcweir } 163cdf0e10cSrcweir 164cdf0e10cSrcweir VbaProject::~VbaProject() 165cdf0e10cSrcweir { 166cdf0e10cSrcweir } 167cdf0e10cSrcweir 168cdf0e10cSrcweir void VbaProject::importVbaProject( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) 169cdf0e10cSrcweir { 170cdf0e10cSrcweir if( rVbaPrjStrg.isStorage() ) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir // load the code modules and forms 173cdf0e10cSrcweir if( isImportVba() ) 174cdf0e10cSrcweir importVba( rVbaPrjStrg, rGraphicHelper, bDefaultColorBgr ); 175cdf0e10cSrcweir // copy entire storage into model 176cdf0e10cSrcweir if( isExportVba() ) 177cdf0e10cSrcweir copyStorage( rVbaPrjStrg ); 178cdf0e10cSrcweir } 179cdf0e10cSrcweir } 180cdf0e10cSrcweir 181cdf0e10cSrcweir void VbaProject::registerMacroAttacher( const VbaMacroAttacherRef& rxAttacher ) 182cdf0e10cSrcweir { 183cdf0e10cSrcweir OSL_ENSURE( rxAttacher.get(), "VbaProject::registerMacroAttacher - unexpected empty reference" ); 184cdf0e10cSrcweir maMacroAttachers.push_back( rxAttacher ); 185cdf0e10cSrcweir } 186cdf0e10cSrcweir 187cdf0e10cSrcweir bool VbaProject::hasModules() const 188cdf0e10cSrcweir { 189cdf0e10cSrcweir return mxBasicLib.is() && mxBasicLib->hasElements(); 190cdf0e10cSrcweir } 191cdf0e10cSrcweir 192cdf0e10cSrcweir bool VbaProject::hasModule( const OUString& rModuleName ) const 193cdf0e10cSrcweir { 194cdf0e10cSrcweir return mxBasicLib.is() && mxBasicLib->hasByName( rModuleName ); 195cdf0e10cSrcweir } 196cdf0e10cSrcweir 197cdf0e10cSrcweir bool VbaProject::hasDialogs() const 198cdf0e10cSrcweir { 199cdf0e10cSrcweir return mxDialogLib.is() && mxDialogLib->hasElements(); 200cdf0e10cSrcweir } 201cdf0e10cSrcweir 202cdf0e10cSrcweir bool VbaProject::hasDialog( const OUString& rDialogName ) const 203cdf0e10cSrcweir { 204cdf0e10cSrcweir return mxDialogLib.is() && mxDialogLib->hasByName( rDialogName ); 205cdf0e10cSrcweir } 206cdf0e10cSrcweir 207cdf0e10cSrcweir // protected ------------------------------------------------------------------ 208cdf0e10cSrcweir 209cdf0e10cSrcweir void VbaProject::addDummyModule( const OUString& rName, sal_Int32 nType ) 210cdf0e10cSrcweir { 211cdf0e10cSrcweir OSL_ENSURE( rName.getLength() > 0, "VbaProject::addDummyModule - missing module name" ); 212cdf0e10cSrcweir maDummyModules[ rName ] = nType; 213cdf0e10cSrcweir } 214cdf0e10cSrcweir 215cdf0e10cSrcweir void VbaProject::prepareImport() 216cdf0e10cSrcweir { 217cdf0e10cSrcweir } 218cdf0e10cSrcweir 219cdf0e10cSrcweir void VbaProject::finalizeImport() 220cdf0e10cSrcweir { 221cdf0e10cSrcweir } 222cdf0e10cSrcweir 223cdf0e10cSrcweir // private -------------------------------------------------------------------- 224cdf0e10cSrcweir 225cdf0e10cSrcweir Reference< XLibraryContainer > VbaProject::getLibraryContainer( sal_Int32 nPropId ) 226cdf0e10cSrcweir { 227cdf0e10cSrcweir PropertySet aDocProp( mxDocModel ); 228cdf0e10cSrcweir Reference< XLibraryContainer > xLibContainer( aDocProp.getAnyProperty( nPropId ), UNO_QUERY ); 229cdf0e10cSrcweir return xLibContainer; 230cdf0e10cSrcweir } 231cdf0e10cSrcweir 232cdf0e10cSrcweir Reference< XNameContainer > VbaProject::openLibrary( sal_Int32 nPropId, bool bCreateMissing ) 233cdf0e10cSrcweir { 234cdf0e10cSrcweir Reference< XNameContainer > xLibrary; 235cdf0e10cSrcweir try 236cdf0e10cSrcweir { 237cdf0e10cSrcweir Reference< XLibraryContainer > xLibContainer( getLibraryContainer( nPropId ), UNO_SET_THROW ); 238cdf0e10cSrcweir if( bCreateMissing && !xLibContainer->hasByName( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ ) ) 239cdf0e10cSrcweir xLibContainer->createLibrary( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ ); 240cdf0e10cSrcweir xLibrary.set( xLibContainer->getByName( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ ), UNO_QUERY_THROW ); 241cdf0e10cSrcweir } 242cdf0e10cSrcweir catch( Exception& ) 243cdf0e10cSrcweir { 244cdf0e10cSrcweir } 245cdf0e10cSrcweir OSL_ENSURE( !bCreateMissing || xLibrary.is(), "VbaProject::openLibrary - cannot create library" ); 246cdf0e10cSrcweir return xLibrary; 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir Reference< XNameContainer > VbaProject::createBasicLibrary() 250cdf0e10cSrcweir { 251cdf0e10cSrcweir if( !mxBasicLib.is() ) 252cdf0e10cSrcweir mxBasicLib = openLibrary( PROP_BasicLibraries, true ); 253cdf0e10cSrcweir return mxBasicLib; 254cdf0e10cSrcweir } 255cdf0e10cSrcweir 256cdf0e10cSrcweir Reference< XNameContainer > VbaProject::createDialogLibrary() 257cdf0e10cSrcweir { 258cdf0e10cSrcweir if( !mxDialogLib.is() ) 259cdf0e10cSrcweir mxDialogLib = openLibrary( PROP_DialogLibraries, true ); 260cdf0e10cSrcweir return mxDialogLib; 261cdf0e10cSrcweir } 262cdf0e10cSrcweir 263cdf0e10cSrcweir void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) 264cdf0e10cSrcweir { 265cdf0e10cSrcweir StorageRef xVbaStrg = rVbaPrjStrg.openSubStorage( CREATE_OUSTRING( "VBA" ), false ); 266cdf0e10cSrcweir OSL_ENSURE( xVbaStrg.get(), "VbaProject::importVba - cannot open 'VBA' substorage" ); 267cdf0e10cSrcweir if( !xVbaStrg ) 268cdf0e10cSrcweir return; 269cdf0e10cSrcweir 270cdf0e10cSrcweir /* Read the 'VBA/dir' stream which contains general settings of the VBA 271cdf0e10cSrcweir project such as the text encoding used throughout several streams, and 272cdf0e10cSrcweir a list of all code modules. 273cdf0e10cSrcweir */ 274cdf0e10cSrcweir BinaryXInputStream aInStrm( xVbaStrg->openInputStream( CREATE_OUSTRING( "dir" ) ), true ); 275cdf0e10cSrcweir // VbaInputStream implements decompression 276cdf0e10cSrcweir VbaInputStream aDirStrm( aInStrm ); 277cdf0e10cSrcweir OSL_ENSURE( !aDirStrm.isEof(), "VbaProject::importVba - cannot open 'dir' stream" ); 278cdf0e10cSrcweir if( aDirStrm.isEof() ) 279cdf0e10cSrcweir return; 280cdf0e10cSrcweir 281cdf0e10cSrcweir // virtual call, derived classes may do some preparations 282cdf0e10cSrcweir prepareImport(); 283cdf0e10cSrcweir 284cdf0e10cSrcweir // read all records of the directory 285cdf0e10cSrcweir rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252; 286cdf0e10cSrcweir sal_uInt16 nModuleCount = 0; 287cdf0e10cSrcweir bool bExecutable = isImportVbaExecutable(); 288cdf0e10cSrcweir 289cdf0e10cSrcweir typedef RefMap< OUString, VbaModule > VbaModuleMap; 290cdf0e10cSrcweir VbaModuleMap aModules, aModulesByStrm; 291cdf0e10cSrcweir 292cdf0e10cSrcweir sal_uInt16 nRecId = 0; 293cdf0e10cSrcweir StreamDataSequence aRecData; 294cdf0e10cSrcweir while( VbaHelper::readDirRecord( nRecId, aRecData, aDirStrm ) && (nRecId != VBA_ID_PROJECTEND) ) 295cdf0e10cSrcweir { 296cdf0e10cSrcweir // create record stream object from imported record data 297cdf0e10cSrcweir SequenceInputStream aRecStrm( aRecData ); 298cdf0e10cSrcweir sal_Int32 nRecSize = aRecData.getLength(); 299cdf0e10cSrcweir switch( nRecId ) 300cdf0e10cSrcweir { 301cdf0e10cSrcweir #define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaProject::importVba - invalid record size" ) 302cdf0e10cSrcweir case VBA_ID_PROJECTCODEPAGE: 303cdf0e10cSrcweir { 304cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); 305cdf0e10cSrcweir OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTCODEPAGE record" ); 306cdf0e10cSrcweir rtl_TextEncoding eNewTextEnc = rtl_getTextEncodingFromWindowsCodePage( aRecStrm.readuInt16() ); 307cdf0e10cSrcweir OSL_ENSURE( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW, "VbaProject::importVba - unknown text encoding" ); 308cdf0e10cSrcweir if( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW ) 309cdf0e10cSrcweir eTextEnc = eNewTextEnc; 310cdf0e10cSrcweir } 311cdf0e10cSrcweir break; 312cdf0e10cSrcweir case VBA_ID_PROJECTNAME: 313cdf0e10cSrcweir { 314cdf0e10cSrcweir OUString aPrjName = aRecStrm.readCharArrayUC( nRecSize, eTextEnc ); 315cdf0e10cSrcweir OSL_ENSURE( aPrjName.getLength() > 0, "VbaProject::importVba - invalid project name" ); 316cdf0e10cSrcweir if( aPrjName.getLength() > 0 ) 317cdf0e10cSrcweir maPrjName = aPrjName; 318cdf0e10cSrcweir } 319cdf0e10cSrcweir break; 320cdf0e10cSrcweir case VBA_ID_PROJECTMODULES: 321cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 2 ); 322cdf0e10cSrcweir OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTMODULES record" ); 323cdf0e10cSrcweir aRecStrm >> nModuleCount; 324cdf0e10cSrcweir break; 325cdf0e10cSrcweir case VBA_ID_MODULENAME: 326cdf0e10cSrcweir { 327cdf0e10cSrcweir OUString aName = aRecStrm.readCharArrayUC( nRecSize, eTextEnc ); 328cdf0e10cSrcweir OSL_ENSURE( aName.getLength() > 0, "VbaProject::importVba - invalid module name" ); 329cdf0e10cSrcweir OSL_ENSURE( !aModules.has( aName ), "VbaProject::importVba - multiple modules with the same name" ); 330cdf0e10cSrcweir VbaModuleMap::mapped_type& rxModule = aModules[ aName ]; 331cdf0e10cSrcweir rxModule.reset( new VbaModule( mxContext, mxDocModel, aName, eTextEnc, bExecutable ) ); 332cdf0e10cSrcweir // read all remaining records until the MODULEEND record 333cdf0e10cSrcweir rxModule->importDirRecords( aDirStrm ); 334cdf0e10cSrcweir OSL_ENSURE( !aModulesByStrm.has( rxModule->getStreamName() ), "VbaProject::importVba - multiple modules with the same stream name" ); 335cdf0e10cSrcweir aModulesByStrm[ rxModule->getStreamName() ] = rxModule; 336cdf0e10cSrcweir } 337cdf0e10cSrcweir break; 338cdf0e10cSrcweir #undef OOX_ENSURE_RECORDSIZE 339cdf0e10cSrcweir } 340cdf0e10cSrcweir } 341cdf0e10cSrcweir OSL_ENSURE( nModuleCount == aModules.size(), "VbaProject::importVba - invalid module count" ); 342cdf0e10cSrcweir 343cdf0e10cSrcweir /* The directory does not contain the real type of the modules, it 344cdf0e10cSrcweir distinguishes only between 'procedural' and 'document' (the latter 345cdf0e10cSrcweir includes class and form modules). Now, the exact type of all modules 346cdf0e10cSrcweir will be read from the 'PROJECT' stream. It consists of text lines in 347cdf0e10cSrcweir 'key=value' format which list the code modules by type. 348cdf0e10cSrcweir 349cdf0e10cSrcweir - The line 'document=<modulename>/&HXXXXXXXX' declares document 350cdf0e10cSrcweir modules. These are attached to the Word document (usually called 351cdf0e10cSrcweir 'ThisDocument'), the Excel workbook (usually called 352cdf0e10cSrcweir 'ThisWorkbook'), or single Excel worksheets or chartsheets (usually 353cdf0e10cSrcweir called 'SheetX' or 'ChartX', X being a decimal number). Of course, 354cdf0e10cSrcweir users may rename all these modules. The slash character separates 355cdf0e10cSrcweir an automation server version number (hexadecimal 'XXXXXXXX') from 356cdf0e10cSrcweir the module name. 357cdf0e10cSrcweir - The line 'Module=<modulename>' declares common procedural code 358cdf0e10cSrcweir modules. 359cdf0e10cSrcweir - The line 'Class=<modulename>' declares a class module. 360cdf0e10cSrcweir - The line 'BaseClass=<modulename>' declares a code module attached 361cdf0e10cSrcweir to a user form with the same name. 362cdf0e10cSrcweir */ 363cdf0e10cSrcweir BinaryXInputStream aPrjStrm( rVbaPrjStrg.openInputStream( CREATE_OUSTRING( "PROJECT" ) ), true ); 364cdf0e10cSrcweir OSL_ENSURE( !aPrjStrm.isEof(), "VbaProject::importVba - cannot open 'PROJECT' stream" ); 365cdf0e10cSrcweir // do not exit if this stream does not exist, but proceed to load the modules below 366cdf0e10cSrcweir if( !aPrjStrm.isEof() ) 367cdf0e10cSrcweir { 368cdf0e10cSrcweir TextInputStream aPrjTextStrm( mxContext, aPrjStrm, eTextEnc ); 369cdf0e10cSrcweir OUString aKey, aValue; 370cdf0e10cSrcweir bool bExitLoop = false; 371cdf0e10cSrcweir while( !bExitLoop && !aPrjTextStrm.isEof() ) 372cdf0e10cSrcweir { 373cdf0e10cSrcweir // read a text line from the stream 374cdf0e10cSrcweir OUString aLine = aPrjTextStrm.readLine().trim(); 375cdf0e10cSrcweir sal_Int32 nLineLen = aLine.getLength(); 376cdf0e10cSrcweir // exit if a subsection starts (section name is given in brackets) 377cdf0e10cSrcweir bExitLoop = (nLineLen >= 2) && (aLine[ 0 ] == '[') && (aLine[ nLineLen - 1 ] == ']'); 378cdf0e10cSrcweir if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) ) 379cdf0e10cSrcweir { 380cdf0e10cSrcweir sal_Int32 nType = ModuleType::UNKNOWN; 381cdf0e10cSrcweir if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Document" ) ) ) 382cdf0e10cSrcweir { 383cdf0e10cSrcweir nType = ModuleType::DOCUMENT; 384cdf0e10cSrcweir // strip automation server version from module names 385cdf0e10cSrcweir sal_Int32 nSlashPos = aValue.indexOf( '/' ); 386cdf0e10cSrcweir if( nSlashPos >= 0 ) 387cdf0e10cSrcweir aValue = aValue.copy( 0, nSlashPos ); 388cdf0e10cSrcweir } 389cdf0e10cSrcweir else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Module" ) ) ) 390cdf0e10cSrcweir nType = ModuleType::NORMAL; 391cdf0e10cSrcweir else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Class" ) ) ) 392cdf0e10cSrcweir nType = ModuleType::CLASS; 393cdf0e10cSrcweir else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "BaseClass" ) ) ) 394cdf0e10cSrcweir nType = ModuleType::FORM; 395cdf0e10cSrcweir 396cdf0e10cSrcweir if( (nType != ModuleType::UNKNOWN) && (aValue.getLength() > 0) ) 397cdf0e10cSrcweir { 398cdf0e10cSrcweir OSL_ENSURE( aModules.has( aValue ), "VbaProject::importVba - module not found" ); 399cdf0e10cSrcweir if( VbaModule* pModule = aModules.get( aValue ).get() ) 400cdf0e10cSrcweir pModule->setType( nType ); 401cdf0e10cSrcweir } 402cdf0e10cSrcweir } 403cdf0e10cSrcweir } 404cdf0e10cSrcweir } 405cdf0e10cSrcweir 406cdf0e10cSrcweir // create empty dummy modules 407cdf0e10cSrcweir VbaModuleMap aDummyModules; 408cdf0e10cSrcweir for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt ) 409cdf0e10cSrcweir { 410cdf0e10cSrcweir OSL_ENSURE( !aModules.has( aIt->first ) && !aDummyModules.has( aIt->first ), "VbaProject::importVba - multiple modules with the same name" ); 411cdf0e10cSrcweir VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ]; 412cdf0e10cSrcweir rxModule.reset( new VbaModule( mxContext, mxDocModel, aIt->first, eTextEnc, bExecutable ) ); 413cdf0e10cSrcweir rxModule->setType( aIt->second ); 414cdf0e10cSrcweir } 415cdf0e10cSrcweir 416cdf0e10cSrcweir /* Now it is time to load the source code. All modules will be inserted 417cdf0e10cSrcweir into the Basic library of the document specified by the 'maPrjName' 418cdf0e10cSrcweir member. Do not create the Basic library, if there are no modules 419cdf0e10cSrcweir specified. */ 420cdf0e10cSrcweir if( !aModules.empty() || !aDummyModules.empty() ) try 421cdf0e10cSrcweir { 422cdf0e10cSrcweir // get the model factory and the basic library 423cdf0e10cSrcweir Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW ); 424cdf0e10cSrcweir Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW ); 425cdf0e10cSrcweir 426cdf0e10cSrcweir /* Set library container to VBA compatibility mode. This will create 427cdf0e10cSrcweir the VBA Globals object and store it in the Basic manager of the 428cdf0e10cSrcweir document. */ 429cdf0e10cSrcweir try 430cdf0e10cSrcweir { 431cdf0e10cSrcweir Reference< XVBACompatibility >( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True ); 432cdf0e10cSrcweir } 433cdf0e10cSrcweir catch( Exception& ) 434cdf0e10cSrcweir { 435cdf0e10cSrcweir } 436cdf0e10cSrcweir 437cdf0e10cSrcweir // try to get access to document objects related to code modules 438cdf0e10cSrcweir Reference< XNameAccess > xDocObjectNA; 439cdf0e10cSrcweir try 440cdf0e10cSrcweir { 441cdf0e10cSrcweir xDocObjectNA.set( xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAObjectModuleObjectProvider" ) ), UNO_QUERY ); 442cdf0e10cSrcweir } 443cdf0e10cSrcweir catch( Exception& ) 444cdf0e10cSrcweir { 445cdf0e10cSrcweir // not all documents support this 446cdf0e10cSrcweir } 447cdf0e10cSrcweir 448cdf0e10cSrcweir if( xBasicLib.is() ) 449cdf0e10cSrcweir { 450cdf0e10cSrcweir // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref 451cdf0e10cSrcweir aModules.forEachMem( &VbaModule::createAndImportModule, 452cdf0e10cSrcweir ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ), 453cdf0e10cSrcweir ::boost::cref( xDocObjectNA ) ); 454cdf0e10cSrcweir 455cdf0e10cSrcweir // create empty dummy modules 456cdf0e10cSrcweir aDummyModules.forEachMem( &VbaModule::createEmptyModule, 457cdf0e10cSrcweir ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) ); 458cdf0e10cSrcweir } 459cdf0e10cSrcweir } 460cdf0e10cSrcweir catch( Exception& ) 461cdf0e10cSrcweir { 462cdf0e10cSrcweir } 463cdf0e10cSrcweir 464cdf0e10cSrcweir /* Load the forms. The file format specification requires that a module 465cdf0e10cSrcweir must exist for every form. We are a bit more tolerant and scan the 466cdf0e10cSrcweir project storage for all form substorages. This may 'repair' broken VBA 467cdf0e10cSrcweir storages that misses to mention a module for an existing form. */ 468cdf0e10cSrcweir ::std::vector< OUString > aElements; 469cdf0e10cSrcweir rVbaPrjStrg.getElementNames( aElements ); 470cdf0e10cSrcweir for( ::std::vector< OUString >::iterator aIt = aElements.begin(), aEnd = aElements.end(); aIt != aEnd; ++aIt ) 471cdf0e10cSrcweir { 472cdf0e10cSrcweir // try to open the element as storage 473cdf0e10cSrcweir if( !aIt->equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VBA" ) ) ) 474cdf0e10cSrcweir { 475cdf0e10cSrcweir StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( *aIt, false ); 476cdf0e10cSrcweir if( xSubStrg.get() ) try 477cdf0e10cSrcweir { 478cdf0e10cSrcweir // resolve module name from storage name (which equals the module stream name) 479cdf0e10cSrcweir VbaModule* pModule = aModulesByStrm.get( *aIt ).get(); 480cdf0e10cSrcweir OSL_ENSURE( pModule && (pModule->getType() == ModuleType::FORM), 481cdf0e10cSrcweir "VbaProject::importVba - form substorage without form module" ); 482cdf0e10cSrcweir OUString aModuleName; 483cdf0e10cSrcweir if( pModule ) 484cdf0e10cSrcweir aModuleName = pModule->getName(); 485cdf0e10cSrcweir 486cdf0e10cSrcweir // create and import the form 487cdf0e10cSrcweir Reference< XNameContainer > xDialogLib( createDialogLibrary(), UNO_SET_THROW ); 488cdf0e10cSrcweir VbaUserForm aForm( mxContext, mxDocModel, rGraphicHelper, bDefaultColorBgr ); 489cdf0e10cSrcweir aForm.importForm( xDialogLib, *xSubStrg, aModuleName, eTextEnc ); 490cdf0e10cSrcweir } 491cdf0e10cSrcweir catch( Exception& ) 492cdf0e10cSrcweir { 493cdf0e10cSrcweir } 494cdf0e10cSrcweir } 495cdf0e10cSrcweir } 496cdf0e10cSrcweir 497cdf0e10cSrcweir // attach macros to registered objects 498cdf0e10cSrcweir attachMacros(); 499cdf0e10cSrcweir // virtual call, derived classes may do some more processing 500cdf0e10cSrcweir finalizeImport(); 501cdf0e10cSrcweir } 502cdf0e10cSrcweir 503cdf0e10cSrcweir void VbaProject::attachMacros() 504cdf0e10cSrcweir { 505cdf0e10cSrcweir if( !maMacroAttachers.empty() && mxContext.is() ) try 506cdf0e10cSrcweir { 507cdf0e10cSrcweir Reference< XMultiComponentFactory > xFactory( mxContext->getServiceManager(), UNO_SET_THROW ); 508cdf0e10cSrcweir Sequence< Any > aArgs( 2 ); 509cdf0e10cSrcweir aArgs[ 0 ] <<= mxDocModel; 510cdf0e10cSrcweir aArgs[ 1 ] <<= maPrjName; 511cdf0e10cSrcweir Reference< XVBAMacroResolver > xResolver( xFactory->createInstanceWithArgumentsAndContext( 512cdf0e10cSrcweir CREATE_OUSTRING( "com.sun.star.script.vba.VBAMacroResolver" ), aArgs, mxContext ), UNO_QUERY_THROW ); 513cdf0e10cSrcweir maMacroAttachers.forEachMem( &VbaMacroAttacherBase::resolveAndAttachMacro, ::boost::cref( xResolver ) ); 514cdf0e10cSrcweir } 515cdf0e10cSrcweir catch( Exception& ) 516cdf0e10cSrcweir { 517cdf0e10cSrcweir } 518cdf0e10cSrcweir } 519cdf0e10cSrcweir 520cdf0e10cSrcweir void VbaProject::copyStorage( StorageBase& rVbaPrjStrg ) 521cdf0e10cSrcweir { 522cdf0e10cSrcweir if( mxContext.is() ) try 523cdf0e10cSrcweir { 524cdf0e10cSrcweir Reference< XStorageBasedDocument > xStorageBasedDoc( mxDocModel, UNO_QUERY_THROW ); 525cdf0e10cSrcweir Reference< XStorage > xDocStorage( xStorageBasedDoc->getDocumentStorage(), UNO_QUERY_THROW ); 526cdf0e10cSrcweir { 527cdf0e10cSrcweir const sal_Int32 nOpenMode = ElementModes::SEEKABLE | ElementModes::WRITE | ElementModes::TRUNCATE; 528cdf0e10cSrcweir Reference< XStream > xDocStream( xDocStorage->openStreamElement( CREATE_OUSTRING( "_MS_VBA_Macros" ), nOpenMode ), UNO_SET_THROW ); 529cdf0e10cSrcweir OleStorage aDestStorage( mxContext, xDocStream, false ); 530cdf0e10cSrcweir rVbaPrjStrg.copyStorageToStorage( aDestStorage ); 531cdf0e10cSrcweir aDestStorage.commit(); 532cdf0e10cSrcweir } 533cdf0e10cSrcweir Reference< XTransactedObject >( xDocStorage, UNO_QUERY_THROW )->commit(); 534cdf0e10cSrcweir } 535cdf0e10cSrcweir catch( Exception& ) 536cdf0e10cSrcweir { 537cdf0e10cSrcweir } 538cdf0e10cSrcweir } 539cdf0e10cSrcweir 540cdf0e10cSrcweir // ============================================================================ 541cdf0e10cSrcweir 542cdf0e10cSrcweir } // namespace ole 543cdf0e10cSrcweir } // namespace oox 544