You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
11 KiB
C#

namespace com.azkoss.excellite
{
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
internal class UnmanagedStorage : StructuredStorageFileBase
{
// Methods
public UnmanagedStorage(string fileName, bool create)
{
OLE_MODE ole_mode1;
SecurityPermission permission1 = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
if (create)
{
ole_mode1 = OLE_MODE.STGM_CREATE | (OLE_MODE.STGM_SHARE_EXCLUSIVE | OLE_MODE.STGM_READWRITE);
try
{
permission1.Assert();
SafeNativeMethods.StgCreateDocfile(fileName, (int) ole_mode1, 0, out this.storage);
}
catch
{
throw new Exception("Need to have unmanaged code rights to execute this code.");
}
if (this.storage == null)
{
throw new IOException("Can't create file. Is file with the \"" + fileName + "\" name used by another process?");
}
}
else
{
ole_mode1 = OLE_MODE.STGM_SHARE_EXCLUSIVE | OLE_MODE.STGM_READWRITE;
try
{
permission1.Assert();
SafeNativeMethods.StgOpenStorage(fileName, null, (int) ole_mode1, IntPtr.Zero, 0, out this.storage);
}
catch
{
throw new Exception("Need to have unmanaged code rights to execute this code.");
}
if (this.storage == null)
{
throw new IOException("Can't open file. Maybe file with the \"" + fileName + "\" name doesn't exist, is not in application folder or is used by another process? Only XLS files from Excel 97 and on are supported.");
}
}
}
protected override void Dispose(bool disposing)
{
if (this.storage != null)
{
if (disposing)
{
this.storage.Commit(0);
}
Marshal.ReleaseComObject(this.storage);
this.storage = null;
}
}
public override byte[] ReadStream(string name)
{
UCOMIStream stream1;
STATSTG statstg1;
if (this.Disposed)
{
throw new ObjectDisposedException("UnmanagedStorage");
}
OLE_MODE ole_mode1 = OLE_MODE.STGM_SHARE_EXCLUSIVE | OLE_MODE.STGM_READWRITE;
try
{
this.storage.OpenStream(name, IntPtr.Zero, (uint) ole_mode1, 0, out stream1);
}
catch (COMException)
{
throw new Exception("Provided file is not a valid BIFF8 file. Only XLS files from Excel 97 and on are supported.");
}
if (stream1 == null)
{
throw new Exception("Can't open OLE2 stream.");
}
stream1.Stat(out statstg1, 1);
byte[] buffer1 = new byte[statstg1.cbSize];
GCHandle handle1 = GCHandle.Alloc(buffer1, GCHandleType.Pinned);
stream1.Read(buffer1, (int) statstg1.cbSize, IntPtr.Zero);
handle1.Free();
return buffer1;
}
public override void WriteStream(string name, byte[] buffer)
{
UCOMIStream stream1;
if (this.Disposed)
{
throw new ObjectDisposedException("UnmanagedStorage");
}
OLE_MODE ole_mode1 = OLE_MODE.STGM_SHARE_EXCLUSIVE | OLE_MODE.STGM_READWRITE;
this.storage.CreateStream(name, (uint) ole_mode1, 0, 0, out stream1);
if (stream1 == null)
{
throw new Exception("Can't create OLE2 stream.");
}
GCHandle handle1 = GCHandle.Alloc(buffer, GCHandleType.Pinned);
stream1.Write(buffer, buffer.Length, IntPtr.Zero);
handle1.Free();
stream1.Commit(0);
Marshal.ReleaseComObject(stream1);
}
// Properties
protected override bool Disposed
{
get
{
return (this.storage == null);
}
}
// Fields
private SafeNativeMethods.IStorage storage;
// Nested Types
[Flags]
private enum OLE_MODE
{
// Fields
STGM_CONVERT = 0x20000,
STGM_CREATE = 0x1000,
STGM_DELETEONRELEASE = 0x4000000,
STGM_DIRECT = 0,
STGM_DIRECT_SWMR = 0x400000,
STGM_FAILIFTHERE = 0,
STGM_NOSCRATCH = 0x100000,
STGM_NOSNAPSHOT = 0x200000,
STGM_PRIORITY = 0x40000,
STGM_READ = 0,
STGM_READWRITE = 2,
STGM_SHARE_DENY_NONE = 0x40,
STGM_SHARE_DENY_READ = 0x30,
STGM_SHARE_DENY_WRITE = 0x20,
STGM_SHARE_EXCLUSIVE = 0x10,
STGM_SIMPLE = 0x8000000,
STGM_TRANSACTED = 0x10000,
STGM_WRITE = 1
}
private class SafeNativeMethods
{
// Methods
private SafeNativeMethods()
{
}
[DllImport("ole32.dll", CharSet=CharSet.Unicode)]
internal static extern int StgCreateDocfile(string filename, int mode, int reserved, out IStorage storage);
[DllImport("ole32.dll", CharSet=CharSet.Unicode)]
internal static extern int StgOpenStorage(string filename, IStorage lastStorage, int mode, IntPtr pSNB, int reserved, out IStorage newStorage);
// Nested Types
[StructLayout(LayoutKind.Sequential)]
internal struct _FILETIME
{
public uint dwHighDateTime;
public uint dwLowDateTime;
public _FILETIME(uint dwHighDateTime, uint dwLowDateTime)
{
this.dwHighDateTime = dwHighDateTime;
this.dwLowDateTime = dwLowDateTime;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct _ULARGE_INTEGER
{
public ulong QuadPart;
public _ULARGE_INTEGER(ulong QuadPart)
{
this.QuadPart = QuadPart;
}
}
[Guid("0000000d-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss]
internal interface IEnumSTATSTG
{
int Clone(out UnmanagedStorage.SafeNativeMethods.IEnumSTATSTG ppenum);
int Next([In] uint celt, out UnmanagedStorage.SafeNativeMethods.tagSTATSTG rgelt, out uint pceltFetched);
int RemoteNext([In] uint celt, out UnmanagedStorage.SafeNativeMethods.tagSTATSTG rgelt, out uint pceltFetched);
int Reset();
int Skip([In] uint celt);
}
[ComConversionLoss, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000b-0000-0000-c000-000000000046")]
internal interface IStorage
{
void CreateStream([In] string pwcsName, [In] uint grfMode, [In] uint reserved1, [In] uint reserved2, out UCOMIStream ppstm);
void OpenStream([In] string pwcsName, [In] IntPtr reserved1, [In] uint grfMode, [In] uint reserved2, out UCOMIStream ppstm);
void CreateStorage([In] string pwcsName, [In] uint grfMode, [In] uint reserved1, [In] uint reserved2, out UnmanagedStorage.SafeNativeMethods.IStorage ppstg);
void OpenStorage([In] string pwcsName, [In] UnmanagedStorage.SafeNativeMethods.IStorage pstgPriority, [In] uint grfMode, [In] ref UnmanagedStorage.SafeNativeMethods.tagRemSNB snbExclude, [In] uint reserved, out UnmanagedStorage.SafeNativeMethods.IStorage ppstg);
void CopyTo([In] uint ciidExclude, [In] ref Guid rgiidExclude, [In] ref UnmanagedStorage.SafeNativeMethods.tagRemSNB snbExclude, [In] UnmanagedStorage.SafeNativeMethods.IStorage pstgDest);
void MoveElementTo([In] string pwcsName, [In] UnmanagedStorage.SafeNativeMethods.IStorage pstgDest, [In] string pwcsNewName, [In] uint grfFlags);
void Commit([In] uint grfCommitFlags);
void Revert();
int EnumElements([In] int reserved1, [In] IntPtr reserved2, [In] int reserved3, out UnmanagedStorage.SafeNativeMethods.IEnumSTATSTG ppenum);
void DestroyElement([In] string pwcsName);
void RenameElement([In] string pwcsOldName, [In] string pwcsNewName);
void SetElementTimes([In] string pwcsName, [In] ref UnmanagedStorage.SafeNativeMethods._FILETIME pctime, [In] ref UnmanagedStorage.SafeNativeMethods._FILETIME patime, [In] ref UnmanagedStorage.SafeNativeMethods._FILETIME pmtime);
void SetClass([In] ref Guid clsid);
void SetStateBits([In] uint grfStateBits, [In] uint grfMask);
void Stat(out UnmanagedStorage.SafeNativeMethods.tagSTATSTG pstatstg, [In] uint grfStatFlag);
}
[StructLayout(LayoutKind.Sequential), ComConversionLoss]
internal struct tagRemSNB
{
[ComConversionLoss]
public IntPtr rgString;
public uint ulCntChar;
public uint ulCntStr;
public tagRemSNB(IntPtr rgString, uint ulCntChar, uint ulCntStr)
{
this.rgString = rgString;
this.ulCntChar = ulCntChar;
this.ulCntStr = ulCntStr;
}
}
[StructLayout(LayoutKind.Sequential), ComConversionLoss]
internal struct tagSTATSTG
{
public UnmanagedStorage.SafeNativeMethods._FILETIME atime;
public UnmanagedStorage.SafeNativeMethods._ULARGE_INTEGER cbSize;
public Guid clsid;
public UnmanagedStorage.SafeNativeMethods._FILETIME ctime;
public uint grfLocksSupported;
public uint grfMode;
public uint grfStateBits;
public UnmanagedStorage.SafeNativeMethods._FILETIME mtime;
public string pwcsName;
public uint reserved;
public uint Type;
public tagSTATSTG(UnmanagedStorage.SafeNativeMethods._FILETIME atime, UnmanagedStorage.SafeNativeMethods._ULARGE_INTEGER cbSize, Guid clsid, UnmanagedStorage.SafeNativeMethods._FILETIME ctime, uint grfLocksSupported, uint grfMode, uint grfStateBits, UnmanagedStorage.SafeNativeMethods._FILETIME mtime, string pwcsName, uint reserved, uint Type)
{
this.atime = atime;
this.cbSize = cbSize;
this.clsid = clsid;
this.ctime = ctime;
this.grfLocksSupported = grfLocksSupported;
this.grfMode = grfMode;
this.grfStateBits = grfStateBits;
this.mtime = mtime;
this.pwcsName = pwcsName;
this.reserved = reserved;
this.Type = Type;
}
}
}
}
}