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