.NET tantalizingly exposes StorageInfo
and StreamInfo
as public
classes, but hides the seminal StorageRoot
as an internal
class, leaving the user no way of creating or opening a Structured Storage from a file or stream.
Microsoft's Reference Source details the source behind StorageRoot
which inherits from StorageInfo
, so rather than copy the code, I've chosen to expose the static methods of StorageRoot
via reflection, so that I can get a reference to the root storage of a File
or Stream
. I've also exposed a Close
method to close an open root StorageInfo
.
using System;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
namespace StructuredStoreageTest
{
public static class StorageRoot
{
public static StorageInfo CreateOnStream(Stream baseStream)
{
return (StorageInfo)InvokeStorageRootMethod(null, "CreateOnStream", baseStream);
}
public static StorageInfo CreateOnStream(Stream baseStream, FileMode mode)
{
return (StorageInfo)InvokeStorageRootMethod(null, "CreateOnStream", baseStream, mode);
}
public static StorageInfo Open(string path)
{
return (StorageInfo)InvokeStorageRootMethod(null, "Open", path);
}
public static StorageInfo Open(string path, FileMode mode)
{
return (StorageInfo)InvokeStorageRootMethod(null, "Open", path, mode);
}
public static StorageInfo Open(string path, FileMode mode, FileAccess access)
{
return (StorageInfo)InvokeStorageRootMethod(null, "Open", path, mode, access);
}
public static StorageInfo Open(string path, FileMode mode, FileAccess access, FileShare share)
{
return (StorageInfo)InvokeStorageRootMethod(null, "Open", path, mode, access, share);
}
public static StorageInfo Open(string path, FileMode mode, FileAccess access, FileShare share, int sectorSize)
{
return (StorageInfo)InvokeStorageRootMethod(null, "Open", path, mode, access, share, sectorSize);
}
public static void Close(StorageInfo storageRoot)
{
InvokeStorageRootMethod(storageRoot, "Close");
}
private static object InvokeStorageRootMethod(StorageInfo storageRoot, string methodName, params object[] methodArgs)
{
Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot", true, false);
return storageRootType.InvokeMember(methodName,
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.InvokeMethod,
null, storageRoot, methodArgs);
}
}
}
I can then use StorageRoot
as follows:
MemoryStream myStream = new MemoryStream(streamBytes);
StorageInfo myRoot = StorageRoot.CreateOnStream(myStream);
StreamInfo dataStreamInfo = myRoot.GetStreamInfo("data");
Stream dataStream = dataStreamInfo.GetStream();
//read/process the stream
dataStream.Dispose();
StorageRoot.Close(myRoot);
Is relying upon Reflection the best alternative here? I could reproduce the StorageRoot
code from Reference Source, and make StorageRoot
an instance class, I suppose.
internal
implementation. Using the public API would entail inheritingStorageInfo
and making an entirely new implementation. This solution enables creating/opening the internal structured storage of - entirely hypothetical idea here - say, an MS-Access form or report, and access things that aren't otherwise accessible, not even through interop assemblies and the host application object model. \$\endgroup\$