Problem
While we generate PowerPoint add-ins with embedded VBA projects, we don't verify that the internal OLE storage structure is correct. PowerPoint may reject add-ins if required VBA streams are missing or malformed, even if the outer OpenXML package is valid.
The VBA project is stored as an OLE compound file (vbaProject.bin) inside the add-in, and it must contain specific streams and storage structures that PowerPoint expects.
What needs to be done
Add a test that opens the generated .ppam file, extracts the embedded VBA project OLE storage, and validates its internal structure using the OpenMcdf library.
Required validations
The test should verify these OLE streams exist and are non-empty:
-
Root-level streams:
PROJECT - Project metadata and module list
PROJECTwm - Module name records
-
VBA storage (sub-storage named VBA):
_VBA_PROJECT - VBA project header with version constants
dir - Directory stream containing Information/References/Modules records
- Module streams - One stream per module/class (named after each module)
-
Optional validation: Check that the dir stream begins with a valid InformationRecord signature
Implementation guidance
Suggested location
Create a new test class under tests/VbaCompiler.Tests/Streams/ such as VbaOleStorageValidationTests.cs
Key steps
// 1. Generate the add-in
var outputStream = new MemoryStream();
compiler.CompilePowerPointMacroFile(outputStream, "output.ppam");
// 2. Extract VBA project binary
outputStream.Position = 0;
using var presentation = PresentationDocument.Open(outputStream, false);
var vbaProjectStream = presentation.PresentationPart.VbaProjectPart.GetStream();
// 3. Load as OLE compound file
var vbaBytes = new byte[vbaProjectStream.Length];
vbaProjectStream.Read(vbaBytes, 0, vbaBytes.Length);
using var oleStream = new MemoryStream(vbaBytes);
using var compoundFile = new CompoundFile(oleStream, CFSUpdateMode.ReadOnly, CFSConfiguration.LeaveOpen);
// 4. Verify root-level streams
Assert.True(compoundFile.RootStorage.ExistsStream("PROJECT"));
Assert.True(compoundFile.RootStorage.ExistsStream("PROJECTwm"));
// 5. Verify VBA storage and its streams
Assert.True(compoundFile.RootStorage.ExistsStorage("VBA"));
var vbaStorage = compoundFile.RootStorage.GetStorage("VBA");
Assert.True(vbaStorage.ExistsStream("_VBA_PROJECT"));
Assert.True(vbaStorage.ExistsStream("dir"));
// 6. Verify module streams exist (one per module added)
Assert.True(vbaStorage.ExistsStream("Module1")); // adjust based on test modules
// 7. Verify streams have content
var dirStream = vbaStorage.GetStream("dir");
Assert.True(dirStream.Size > 0);
Important notes
- Use
CFSUpdateMode.ReadOnly when opening the OLE file
- Use
CFSConfiguration.LeaveOpen to prevent disposing the underlying stream prematurely
- Reset stream positions (
Position = 0) before reading
- Test with multiple module types (standard modules, class modules) to ensure all generate their streams correctly
Why this matters
The VBA OLE structure is what PowerPoint actually reads to load and execute macros. Even if the OpenXML package is valid, PowerPoint will fail to load the add-in if these internal streams are missing or corrupted. This test ensures we're generating fully compliant VBA projects that Office applications can actually use.
Related files
src/VbaCompiler/VbaCompiler.cs - CompilePowerPointMacroFile and CompileVbaProject methods
src/VbaCompiler/Vba/VbaProjectStream.cs - Writes _VBA_PROJECT stream
src/VbaCompiler/Vba/DirStream.cs - Builds dir stream
src/VbaCompiler/Vba/ModuleStream.cs - Writes individual module streams
src/VbaCompiler/Vba/ProjectRecord.cs - Populates PROJECT stream
src/VbaCompiler/Vba/ProjectWmRecord.cs - Writes PROJECTwm stream
Dependencies
The project already uses OpenMcdf for OLE manipulation, so no new dependencies are needed.
Problem
While we generate PowerPoint add-ins with embedded VBA projects, we don't verify that the internal OLE storage structure is correct. PowerPoint may reject add-ins if required VBA streams are missing or malformed, even if the outer OpenXML package is valid.
The VBA project is stored as an OLE compound file (
vbaProject.bin) inside the add-in, and it must contain specific streams and storage structures that PowerPoint expects.What needs to be done
Add a test that opens the generated
.ppamfile, extracts the embedded VBA project OLE storage, and validates its internal structure using theOpenMcdflibrary.Required validations
The test should verify these OLE streams exist and are non-empty:
Root-level streams:
PROJECT- Project metadata and module listPROJECTwm- Module name recordsVBA storage (sub-storage named
VBA):_VBA_PROJECT- VBA project header with version constantsdir- Directory stream containing Information/References/Modules recordsOptional validation: Check that the
dirstream begins with a validInformationRecordsignatureImplementation guidance
Suggested location
Create a new test class under
tests/VbaCompiler.Tests/Streams/such asVbaOleStorageValidationTests.csKey steps
Important notes
CFSUpdateMode.ReadOnlywhen opening the OLE fileCFSConfiguration.LeaveOpento prevent disposing the underlying stream prematurelyPosition = 0) before readingWhy this matters
The VBA OLE structure is what PowerPoint actually reads to load and execute macros. Even if the OpenXML package is valid, PowerPoint will fail to load the add-in if these internal streams are missing or corrupted. This test ensures we're generating fully compliant VBA projects that Office applications can actually use.
Related files
src/VbaCompiler/VbaCompiler.cs-CompilePowerPointMacroFileandCompileVbaProjectmethodssrc/VbaCompiler/Vba/VbaProjectStream.cs- Writes_VBA_PROJECTstreamsrc/VbaCompiler/Vba/DirStream.cs- Buildsdirstreamsrc/VbaCompiler/Vba/ModuleStream.cs- Writes individual module streamssrc/VbaCompiler/Vba/ProjectRecord.cs- PopulatesPROJECTstreamsrc/VbaCompiler/Vba/ProjectWmRecord.cs- WritesPROJECTwmstreamDependencies
The project already uses
OpenMcdffor OLE manipulation, so no new dependencies are needed.