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