转载请注明出处:http://blog.csdn.net/jh_zzz
最近项目中正好用到用 C# 写结构化存储,贴出来与大家共享一下:
结构化存储机制是COM的数据存储的基础,其核心思想是在一个文件内部建立一个类似于文件系统的完整的存储结构,并以存储对象或流对象构成了此类文件系统中树状结构的各个节点,这个包含了类似于文件系统的存储结构的文件也被称为复合文件。
Windows 提供了两个函数用来打开或创建结构化文件存储对象:
public sealed class NativeMethods
...{
private NativeMethods()
...{
}
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, uint grfMode, uint reserved);
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IntPtr pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved);
}
...{
private NativeMethods()
...{
}
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, uint grfMode, uint reserved);
[DllImport("ole32.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
internal static extern IStorage StgOpenStorage([MarshalAs(UnmanagedType.LPWStr)] string pwcsName, IntPtr pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved);
}
这两个函数成功执行后都会返回一个 IStorage 接口指针,调用相应的接口的函数便可以对复合文件进行操作,以下是对 IStorage,ISteam 接口以及相关常量的声明:
public enum StorageMode
...{
Read = 0x0,
Write = 0x1,
ReadWrite = 0x2,
ShareDenyNone = 0x40,
ShareDenyRead = 0x30,
ShareDenyWrite = 0x20,
ShareExclusive = 0x10,
Priority = 0x40000,
Create = 0x1000,
}
[ComImport, Guid("0000000d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATSTG
...{
[PreserveSig]
uint Next(uint celt, [MarshalAs(UnmanagedType.LPArray), Out] STATSTG[] rgelt, out uint pceltFetched);
void Skip(uint celt);
void Reset();
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSTATSTG Clone();
}
[ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStorage
...{
void CreateStream(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStream ppstm);
void OpenStream(string pwcsName, IntPtr reserved1, uint grfMode, uint reserved2, out IStream ppstm);
void CreateStorage(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStorage ppstg);
void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstg);
void CopyTo(uint ciidExclude, IntPtr rgiidExclude, IntPtr snbExclude, IStorage pstgDest);
void MoveElementTo(string pwcsName, IStorage pstgDest, string pwcsNewName, uint grfFlags);
void Commit(uint grfCommitFlags);
void Revert();
void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3, out IEnumSTATSTG ppenum);
void DestroyElement(string pwcsName);
void RenameElement(string pwcsOldName, string pwcsNewName);
void SetElementTimes(string pwcsName, FILETIME pctime, FILETIME patime, FILETIME pmtime);
void SetClass(Guid clsid);
void SetStateBits(uint grfStateBits, uint grfMask);
void Stat(out STATSTG pstatstg, uint grfStatFlag);
}
[ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStream
...{
void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);
void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);
void SetSize(long libNewSize);
void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
void Commit(int grfCommitFlags);
void Revert();
void LockRegion(long libOffset, long cb, int dwLockType);
void UnlockRegion(long libOffset, long cb, int dwLockType);
void Stat(out STATSTG pstatstg, int grfStatFlag);
void Clone(out IStream ppstm);
}
...{
Read = 0x0,
Write = 0x1,
ReadWrite = 0x2,
ShareDenyNone = 0x40,
ShareDenyRead = 0x30,
ShareDenyWrite = 0x20,
ShareExclusive = 0x10,
Priority = 0x40000,
Create = 0x1000,
}
[ComImport, Guid("0000000d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATSTG
...{
[PreserveSig]
uint Next(uint celt, [MarshalAs(UnmanagedType.LPArray), Out] STATSTG[] rgelt, out uint pceltFetched);
void Skip(uint celt);
void Reset();
[return: MarshalAs(UnmanagedType.Interface)]
IEnumSTATSTG Clone();
}
[ComImport, Guid("0000000b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStorage
...{
void CreateStream(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStream ppstm);
void OpenStream(string pwcsName, IntPtr reserved1, uint grfMode, uint reserved2, out IStream ppstm);
void CreateStorage(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStorage ppstg);
void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstg);
void CopyTo(uint ciidExclude, IntPtr rgiidExclude, IntPtr snbExclude, IStorage pstgDest);
void MoveElementTo(string pwcsName, IStorage pstgDest, string pwcsNewName, uint grfFlags);
void Commit(uint grfCommitFlags);
void Revert();
void EnumElements(uint reserved1, IntPtr reserved2, uint reserved3, out IEnumSTATSTG ppenum);
void DestroyElement(string pwcsName);
void RenameElement(string pwcsOldName, string pwcsNewName);
void SetElementTimes(string pwcsName, FILETIME pctime, FILETIME patime, FILETIME pmtime);
void SetClass(Guid clsid);
void SetStateBits(uint grfStateBits, uint grfMask);
void Stat(out STATSTG pstatstg, uint grfStatFlag);
}
[ComImport, Guid("0000000c-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStream
...{
void Read([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);
void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);
void SetSize(long libNewSize);
void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
void Commit(int grfCommitFlags);
void Revert();
void LockRegion(long libOffset, long cb, int dwLockType);
void UnlockRegion(long libOffset, long cb, int dwLockType);
void Stat(out STATSTG pstatstg, int grfStatFlag);
void Clone(out IStream ppstm);
}
为了使用方便,我们又另外包装了 Storage 类:
public sealed class Storage : IDisposable
...{
private bool disposed;
private IStorage storage;
public Storage(IStorage storage)
...{
this.storage = storage;
}
~Storage()
...{
//this.Dispose();
}
public static Storage CreateDocFile(string storageFile, StorageMode mode)
...{
IStorage storage = NativeMethods.StgCreateDocfile(storageFile, (uint)mode, 0);
return new Storage(storage);
}
public static Storage Open(string storageFile, StorageMode mode)
...{
IStorage storage = NativeMethods.StgOpenStorage(storageFile, IntPtr.Zero, (uint)mode, IntPtr.Zero, 0);
return new Storage(storage);
}
public void CopyTo(Storage destinationStorage)
...{
this.storage.CopyTo(0, IntPtr.Zero, IntPtr.Zero, destinationStorage.storage);
}
public Storage OpenStorage(string name, bool autoCreate)
...{
IStorage subStorage;
try
...{
this.storage.OpenStorage(name, null, (uint)(StorageMode.ReadWrite | StorageMode.ShareExclusive), IntPtr.Zero, 0, out subStorage);
}
catch (COMException)
...{
subStorage = null;
}
if (subStorage == null)
...{
if (autoCreate)
return CreateStorage(name);
return null;
}
return new Storage(subStorage);
}
public Storage RecurOpenStorage(string name, bool autoCreate)
...{
string pwcsName;
int pos = name.IndexOf('/');
if (pos > 0)
...{
pwcsName = name.Substring(0, pos);
name = name.Substring(pos + 1);
}
else
...{
pwcsName = name;
name = "";
}
Storage subStorage = OpenStorage(pwcsName, autoCreate);
if (subStorage != null && name.Length > 0)
...{
return
...{
private bool disposed;
private IStorage storage;
public Storage(IStorage storage)
...{
this.storage = storage;
}
~Storage()
...{
//this.Dispose();
}
public static Storage CreateDocFile(string storageFile, StorageMode mode)
...{
IStorage storage = NativeMethods.StgCreateDocfile(storageFile, (uint)mode, 0);
return new Storage(storage);
}
public static Storage Open(string storageFile, StorageMode mode)
...{
IStorage storage = NativeMethods.StgOpenStorage(storageFile, IntPtr.Zero, (uint)mode, IntPtr.Zero, 0);
return new Storage(storage);
}
public void CopyTo(Storage destinationStorage)
...{
this.storage.CopyTo(0, IntPtr.Zero, IntPtr.Zero, destinationStorage.storage);
}
public Storage OpenStorage(string name, bool autoCreate)
...{
IStorage subStorage;
try
...{
this.storage.OpenStorage(name, null, (uint)(StorageMode.ReadWrite | StorageMode.ShareExclusive), IntPtr.Zero, 0, out subStorage);
}
catch (COMException)
...{
subStorage = null;
}
if (subStorage == null)
...{
if (autoCreate)
return CreateStorage(name);
return null;
}
return new Storage(subStorage);
}
public Storage RecurOpenStorage(string name, bool autoCreate)
...{
string pwcsName;
int pos = name.IndexOf('/');
if (pos > 0)
...{
pwcsName = name.Substring(0, pos);
name = name.Substring(pos + 1);
}
else
...{
pwcsName = name;
name = "";
}
Storage subStorage = OpenStorage(pwcsName, autoCreate);
if (subStorage != null && name.Length > 0)
...{
return