xref: /core/oox/source/ole/vbaproject.cxx (revision b3edf85e)
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