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