|
//-----------------------------------------------------------------------------
//
// <copyright file="PrivateUnsafeNativeCompoundFileMethods.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved.
// </copyright>
//
// Description:
// The COM and P/Invoke interop code necessary for the managed compound
// file layer to call the existing APIs in OLE32.DLL.
//
// Note that not everything is properly ported, for example the SNB type
// used in several IStorage methods is just ignored.
//
// WARNING: This class should ONLY be access by SafeNativeCompoundFileMethods class
// although this class is marked as "internal". This is only done because
// TAS cannot be set on the individual member level if the entire class is
// marked as SecurityCritical. This class should be treated as if it is a nested
// private class of SafeNativeCompoundfileMethods.
//
// History:
// 02/01/2006: Microsoft: Seperated from NativeCompoundFileAPIs.cs
// This file holds all unsafe APIs and interfaces
// 05/10/2002: RogerCh: Initial creation.
// 07/31/2002: RogerCh: Add LockBytes support, suppress unmanaged code security.
// 05/20/2003: RogerCh: Ported to WCP tree.
// 05/28/2003: RogerCh: Removed name checks - now handled by LongNameManager
// 02/10/2006: Microsoft: Added the security suppressed CF interfaces and APIs
//
//-----------------------------------------------------------------------------
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using MS.Internal.Interop; // For PROPSPEC and PROPVARIANT.
using System.Security;
using MS.Internal.WindowsBase;
using CultureInfo = System.Globalization.CultureInfo;
namespace MS.Internal.IO.Packaging.CompoundFile
{
// <SecurityNote>
// Critical: These interfaces and APIs have suppress unamanged code attribute set.
// It is up to the wrapper class (SafeNativeCompoundFileMethods) to ensure that the only
// calls that can go through must be either done in Full Trust or with CompoundFileIOPermission.
// </SecurityNote>
[SecurityCritical(SecurityCriticalScope.Everything)]
internal static class UnsafeNativeCompoundFileMethods
{
/////////////////////////////////////////////////////
// Security Suppressed APIs
/////////////////////////////////////////////////////
[DllImport("ole32.dll")]
[SuppressUnmanagedCodeSecurity]
internal static extern int StgCreateDocfileOnILockBytes(
UnsafeNativeILockBytes plkbyt,
int grfMode,
int reserved, // Must be zero
out UnsafeNativeIStorage ppstgOpen
);
[DllImport("ole32.dll")]
[SuppressUnmanagedCodeSecurity]
internal static extern int StgOpenStorageOnILockBytes(
UnsafeNativeILockBytes plkbyt,
UnsafeNativeIStorage pStgPriority, // Most often NULL
int grfMode,
IntPtr snbExclude, // Pointer to SNB struct, not marshalled, must be null.
int reserved, // Must be zero
out UnsafeNativeIStorage ppstgOpen
);
[DllImport("ole32.dll")]
[SuppressUnmanagedCodeSecurity]
internal static extern int StgCreateStorageEx(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName, //Pointer to path of compound file to create
int grfMode, // Specifies the access mode for opening the storage object
int stgfmt, // Specifies the storage file format, 5 is DocFile
int grfAttrs, // Reserved; must be zero
IntPtr pStgOptions,// Pointer to STGOPTIONS, not marshalled, must use NULL.
IntPtr reserved2, // Reserved; must be null
ref Guid riid, // Specifies the GUID of the interface pointer
out UnsafeNativeIStorage ppObjectOpen //Pointer to an interface pointer
);
[DllImport("ole32.dll")]
[SuppressUnmanagedCodeSecurity]
internal static extern int StgOpenStorageEx(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName, //Pointer to path of compound file to create
int grfMode, // Specifies the access mode for opening the storage object
int stgfmt, // Specifies the storage file format, 5 is DocFile
int grfAttrs, // Reserved; must be zero
IntPtr pStgOptions,// Pointer to STGOPTIONS, not marshalled, must use NULL.
IntPtr reserved2, // Reserved; must be null
ref Guid riid, // Specifies the GUID of the interface pointer
out UnsafeNativeIStorage ppObjectOpen //Pointer to an interface pointer
);
[DllImport("ole32.dll")]
[SuppressUnmanagedCodeSecurity]
internal static extern int PropVariantClear(ref PROPVARIANT pvar);
internal class UnsafeLockBytesOnStream : UnsafeNativeILockBytes, IDisposable
{
internal UnsafeLockBytesOnStream( Stream underlyingStream )
{
if( !underlyingStream.CanSeek )
{
throw new NotSupportedException(
SR.Get(SRID.ILockBytesStreamMustSeek));
}
_baseStream = underlyingStream;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose(bool)
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (disposing && (_baseStream != null))
{
// We only set the _baseStream to null without closing it,
// because _baseStream is a reference of an outside stream,
// and was set when this class was constructed. We didn't open
// the stream and should leave the original owner of the stream
// to close it.
_baseStream = null;
}
}
private void CheckDisposed()
{
if (_baseStream==null)
{
throw new ObjectDisposedException(null, SR.Get(SRID.StreamObjectDisposed));
}
}
void UnsafeNativeILockBytes.ReadAt (
UInt64 offset,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] Byte[] pv,
int cb,
out int pcbRead)
{
CheckDisposed();
checked { _baseStream.Seek( (long)offset, SeekOrigin.Begin ); }
pcbRead = _baseStream.Read( pv, 0, cb );
}
void UnsafeNativeILockBytes.WriteAt(
UInt64 offset,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] Byte[] pv,
int cb,
out int pcbWritten)
{
CheckDisposed();
checked { _baseStream.Seek( (long)offset, SeekOrigin.Begin ); }
_baseStream.Write( pv, 0, cb );
// System.IO.Stream.Write does not return the number of bytes
// written. Presumably this means an exception will be thrown
// if fewer than cb bytes are written.
pcbWritten = cb;
}
void UnsafeNativeILockBytes.Flush()
{
CheckDisposed();
_baseStream.Flush();
}
void UnsafeNativeILockBytes.SetSize( UInt64 cb )
{
CheckDisposed();
checked { _baseStream.SetLength((long)cb); }
}
void UnsafeNativeILockBytes.LockRegion(
UInt64 libOffset,
UInt64 cb,
int dwLockType )
{
throw new NotSupportedException();
}
void UnsafeNativeILockBytes.UnlockRegion(
UInt64 libOffset,
UInt64 cb,
int dwLockType )
{
throw new NotSupportedException();
}
void UnsafeNativeILockBytes.Stat(
out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
int grfStatFlag )
{
CheckDisposed();
if ((grfStatFlag & ~(SafeNativeCompoundFileConstants.STATFLAG_NONAME |
SafeNativeCompoundFileConstants.STATFLAG_NOOPEN )) != 0)
{
// validate grfStatFlag's value
throw new ArgumentException(SR.Get(SRID.InvalidArgumentValue, "grfStatFlag", grfStatFlag.ToString(CultureInfo.InvariantCulture)));
}
System.Runtime.InteropServices.ComTypes.STATSTG returnValue = new System.Runtime.InteropServices.ComTypes.STATSTG();
returnValue.grfLocksSupported = 0 ; // No lock supported
returnValue.cbSize = _baseStream.Length;
returnValue.type = SafeNativeCompoundFileConstants.STGTY_LOCKBYTES;
pstatstg = returnValue;
}
private Stream _baseStream;
}
/////////////////////////////////////////////////////
// Security Suppressed Private Interfaces
/////////////////////////////////////////////////////
[Guid("0000000a-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
internal interface UnsafeNativeILockBytes
{
void ReadAt (
UInt64 offset,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] Byte[] pv,
int cb,
out int pcbRead);
void WriteAt(
UInt64 offset,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] Byte[] pv,
int cb,
out int pcbWritten);
void Flush();
void SetSize( UInt64 cb );
void LockRegion(
UInt64 libOffset,
UInt64 cb,
int dwLockType );
void UnlockRegion(
UInt64 libOffset,
UInt64 cb,
int dwLockType );
void Stat(
out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
int grfStatFlag );
}
// Partial interface definition for existing IStorage
[Guid("0000000b-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIStorage
{
[PreserveSig]
int CreateStream(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
int grfMode,
int reserved1,
int reserved2,
out UnsafeNativeIStream ppstm );
[PreserveSig]
int OpenStream(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
int reserved1,
int grfMode,
int reserved2,
out UnsafeNativeIStream ppstm );
[PreserveSig]
int CreateStorage(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
int grfMode,
int reserved1,
int reserved2,
out UnsafeNativeIStorage ppstg );
[PreserveSig]
int OpenStorage(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
UnsafeNativeIStorage pstgPriority,
int grfMode,
IntPtr snbExclude,// Not properly translated, must be NULL anyway
int reserved,
out UnsafeNativeIStorage ppstg );
void CopyTo(
int ciidExclude,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Guid[] rgiidExclude,
IntPtr snbExclude,// Not properly translated, use NULL to avoid `blow-up
UnsafeNativeIStorage ppstg );
void MoveElementTo(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
UnsafeNativeIStorage pstgDest,
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsNewName,
int grfFlags );
void Commit(
int grfCommitFlags );
void Revert();
void EnumElements(
int reserved1,
IntPtr reserved2,
int reserved3,
out UnsafeNativeIEnumSTATSTG ppEnum );
void DestroyElement(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName );
void RenameElement(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsOldName,
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsNewName );
void SetElementTimes(
[In, MarshalAs( UnmanagedType.LPWStr )] string pwcsName,
System.Runtime.InteropServices.ComTypes.FILETIME pctime,
System.Runtime.InteropServices.ComTypes.FILETIME patime,
System.Runtime.InteropServices.ComTypes.FILETIME pmtime );
void SetClass(
ref Guid clsid ); // Hopefully "ref" is how I tell it to use a pointer
void SetStateBits(
int grfStateBits,
int grfMask );
void Stat(
out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
int grfStatFlag );
}
[Guid("0000000c-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIStream
{
// ISequentialStream portion
void Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] Byte[] pv, int cb, out int pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Byte[] pv, int cb, out int pcbWritten);
// IStream portion
void Seek(long dlibMove, int dwOrigin, out long plibNewPosition);
void SetSize(long libNewSize);
void CopyTo(UnsafeNativeIStream pstm, long cb, out long pcbRead, out long 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 System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag);
void Clone(out UnsafeNativeIStream ppstm);
}
[ComImport]
[Guid("0000013A-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIPropertySetStorage
{
void Create(
ref Guid rfmtid,
ref Guid pclsid,
UInt32 grfFlags,
UInt32 grfMode,
out UnsafeNativeIPropertyStorage ppprstg
);
[PreserveSig]
int Open(
ref Guid rfmtid,
UInt32 grfMode,
out UnsafeNativeIPropertyStorage ppprstg
);
void Delete(
ref Guid rfmtid
);
void Enum(
out UnsafeNativeIEnumSTATPROPSETSTG ppenum
);
}
[ComImport]
[Guid("0000013B-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIEnumSTATPROPSETSTG
{
//
// The caller must allocate an array of celt STATPROPSETSTG structures
// to receive the results.
//
// This method is PreserveSig because it can return a non-0 success
// code; S_FALSE => fewer than celt elements were returned.
//
[PreserveSig]
int
Next(
UInt32 celt,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
STATPROPSETSTG rgelt,
out UInt32 pceltFetched
);
void Skip(UInt32 celt);
void Reset();
void Clone(out UnsafeNativeIEnumSTATPROPSETSTG ppenum);
}
[ComImport]
[Guid("00000138-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIPropertyStorage
{
//
// We preserve the HRESULT on this method because we need to distinguish
// between S_OK (we got the properties we asked for) and S_FALSE (none of
// the properties exist).
//
[PreserveSig]
int
ReadMultiple(
UInt32 cpspec,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
PROPSPEC[] rgpspec,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
PROPVARIANT[] rgpropvar
);
void WriteMultiple(
UInt32 cpspec,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
PROPSPEC[] rgpspec,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
PROPVARIANT[] rgpropvar,
uint propidNameFirst
);
void DeleteMultiple(
UInt32 cpspec,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
PROPSPEC[] rgpspec
);
void ReadPropertyNames(
UInt32 cpropid,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
UInt32[] rgpropid,
[Out, MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPWStr,
SizeParamIndex=0)]
string[] rglpwstrName
);
void WritePropertyNames(
UInt32 cpropid,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
UInt32[] rgpropid,
[In, MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPWStr,
SizeParamIndex=0)]
string[] rglpwstrName
);
void DeletePropertyNames(
UInt32 cpropid,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
UInt32[] rgpropid
);
void Commit(
UInt32 grfCommitFlags
);
void Revert();
void Enum(
out UnsafeNativeIEnumSTATPROPSTG ppenum
);
void SetTimes(
ref System.Runtime.InteropServices.ComTypes.FILETIME pctime,
ref System.Runtime.InteropServices.ComTypes.FILETIME patime,
ref System.Runtime.InteropServices.ComTypes.FILETIME pmtime
);
void SetClass(
ref Guid clsid
);
void Stat(
out STATPROPSETSTG pstatpsstg
);
}
[ComImport]
[Guid("00000139-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIEnumSTATPROPSTG
{
//
// The caller must allocate an array of celt STATPROPSTG structures
// to receive the results.
//
// This method is PreserveSig because it can return a non-0 success
// code; S_FALSE => fewer than celt elements were returned.
//
[PreserveSig]
int
Next(
UInt32 celt,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]
STATPROPSTG rgelt,
out UInt32 pceltFetched
);
void Skip(UInt32 celt);
void Reset();
void Clone(out UnsafeNativeIEnumSTATPROPSTG ppenum);
}
[Guid("0000000d-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
[SuppressUnmanagedCodeSecurity]
internal interface UnsafeNativeIEnumSTATSTG
{
void Next(
UInt32 celt,
out System.Runtime.InteropServices.ComTypes.STATSTG rgelt, // This should really be array, but we're OK if we stick with one item at a time.
// Because marshalling an array of structs that have pointers to strings are troublesome.
out UInt32 pceltFetched );
void Skip(
UInt32 celt );
void Reset();
void Clone(
out UnsafeNativeIEnumSTATSTG ppenum );
}
}
}
|