StorageBasedPackageProperties.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / MS / Internal / IO / Packaging / StorageBasedPackageProperties.cs / 1305600 / StorageBasedPackageProperties.cs

                            //------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This class provides access to the package properties of an RM-protected OPC 
//  document. The "package properties" are a subset of the standard OLE property
//  sets SummaryInformation and DocumentSummaryInformation, and include such 
//  properties as Title and Subject.
//
//  An RM-protected OPC document is physically represented by an OLE compound
//  file containing a well-known stream in which an OPC Zip archive, encrypted 
//  in its entirety, is stored. The package properties of an RM-protected OPC
//  document are stored in the standard OLE compound file property set streams, 
//  \005SummaryInformation and \005DocumentSummaryInformation. The contents of 
//  these streams is intended to mirror the corresponding metadata properties
//  stored in the OPC package itself. These properties are duplicated, in the 
//  clear, outside of the encrypted OPC package stream, so that tools such as
//  the Shell can display the properties without having to decrypt the package.
//
//  It is the responsibility of the application to ensure that the properties in 
//  the OLE property set streams are synchronized with the properties in the
//  OPC package. 
// 
// History:
//  06/16/2005: LGolding:   Initial implementation. 
//  09/23/2005: JohnLarc:   Removed from public surface.
//
//-----------------------------------------------------------------------------
 
using System;
using System.IO; 
using System.IO.Packaging; 
using System.Runtime.InteropServices;
using System.Windows; 
using System.Security; // SecurityCritical
using System.Text;      //For UTF-8 encoding.

using MS.Internal; 
using MS.Internal.Interop;
using MS.Internal.IO.Packaging.CompoundFile; 
using MS.Internal.WindowsBase;  //for SecurityHelper. 

// Enable presharp pragma warning suppress directives. 
#pragma warning disable 1634, 1691

namespace MS.Internal.IO.Packaging
{ 
    /// 
    /// This class provides access to the package properties, such as Title and 
    /// Subject, of an RM-protected OPC package. These properties are a subset of 
    /// of the standard OLE property sets SummaryInformation and
    /// DocumentSummaryInformation. 
    /// 
    internal class StorageBasedPackageProperties : PackageProperties, IDisposable
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors

        //
        // The constructor is internal because an application never directly 
        // creates an object of this class. An application obtains an object
        // of this class through the PackageProperties CLR property of the 
        // EncryptedPackageEnvelope class: 
        //
        //      EncryptedPackageEnvelope ep = EncryptedPackageEnvelope.Create("mydoc.xps", ...); 
        //      PackageProperties props = ep.PackageProperties;
        //
        internal
        StorageBasedPackageProperties( 
            StorageRoot root
            ) 
        { 
            _pss = (IPropertySetStorage)root.GetRootIStorage();
 
            //
            // Open the property sets with the same access with which the file itself
            // was opened.
            // 
            _grfMode = SafeNativeCompoundFileConstants.STGM_DIRECT
                        | SafeNativeCompoundFileConstants.STGM_SHARE_EXCLUSIVE; 
            SafeNativeCompoundFileMethods.UpdateModeFlagFromFileAccess(root.OpenAccess, ref _grfMode); 

            OpenPropertyStorage(ref FormatId.SummaryInformation, out _psSummInfo); 
            OpenPropertyStorage(ref FormatId.DocumentSummaryInformation, out _psDocSummInfo);
        }

        ///  
        /// Finalizer.
        ///  
        ~StorageBasedPackageProperties() 
        {
            Dispose(false); 
        }

        #endregion Constructors
 
        //------------------------------------------------------
        // 
        //  Public Properties 
        //
        //----------------------------------------------------- 

        #region Public Properties

        #region SummaryInformation properties 

        ///  
        /// The title. 
        /// 
        public override string Title 
        {
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Title) as string; 
            }
 
            set 
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Title, value); 
            }
        }

        ///  
        /// The topic of the contents.
        ///  
        public override string Subject 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Subject) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Subject, value); 
            }
        } 

        /// 
        /// The primary creator. The identification is environment-specific and
        /// can consist of a name, email address, employee ID, etc. It is 
        /// recommended that this value be only as verbose as necessary to
        /// identify the individual. 
        ///  
        public override string Creator
        { 
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Creator) as string;
            } 

            set 
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Creator, value);
            } 
        }

        /// 
        /// A delimited set of keywords to support searching and indexing. This 
        /// is typically a list of terms that are not available elsewhere in the
        /// properties. 
        ///  
        public override string Keywords
        { 
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Keywords) as string;
            } 

            set 
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Keywords, value);
            } 
        }

        /// 
        /// The description or abstract of the contents. 
        /// 
        public override string Description 
        { 
            get
            { 
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Description) as string;
            }

            set 
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Description, value); 
            } 
        }
 
        /// 
        /// The user who performed the last modification. The identification is
        /// environment-specific and can consist of a name, email address,
        /// employee ID, etc. It is recommended that this value be only as 
        /// verbose as necessary to identify the individual.
        ///  
        public override string LastModifiedBy 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.LastModifiedBy) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.LastModifiedBy, value); 
            }
        } 

        /// 
        /// The revision number. This value indicates the number of saves or
        /// revisions. The application is responsible for updating this value 
        /// after each revision.
        ///  
        public override string Revision 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Revision) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Revision, value); 
            }
        } 

        /// 
        /// The date and time of the last printing.
        ///  
        public override Nullable LastPrinted
        { 
            get 
            {
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.LastPrinted); 
            }

            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.LastPrinted, value);
            } 
        } 

        ///  
        /// The creation date and time.
        /// 
        public override Nullable Created
        { 
            get
            { 
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.DateCreated); 
            }
 
            set
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.DateCreated, value);
            } 
        }
 
        ///  
        /// The date and time of the last modification.
        ///  
        public override Nullable Modified
        {
            get
            { 
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.DateModified);
            } 
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.DateModified, value);
            }
        }
 
        #endregion SummaryInformation properties
 
        #region DocumentSummaryInformation properties 

        ///  
        /// The category. This value is typically used by UI applications to create navigation
        /// controls.
        /// 
        public override string Category 
        {
            get 
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Category) as string;
            } 

            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Category, value); 
            }
        } 
 
        /// 
        /// A unique identifier. 
        /// 
        public override string Identifier
        {
            get 
            {
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Identifier) as string; 
            } 

            set 
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Identifier, value);
            }
        } 

        ///  
        /// The type of content represented, generally defined by a specific 
        /// use and intended audience. Example values include "Whitepaper"
        /// and "Exam". (This property is distinct from 
        /// MIME content types as defined in RFC 2045.)
        /// 
        public override string ContentType
        { 
            get
            { 
                string contentType = GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType) as string; 
                if (contentType == null)
                { 
                    return contentType;
                }
                else
                { 
                    //Creating a ContentType object to validate the content type string.
                    //Can replace this later with a static method to validate the content type. 
                    return new ContentType(contentType).ToString(); 
                }
            } 

            set
            {
                if (value == null) 
                {
                    //indicates that the property should be deleted. 
                    SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType, value); 
                }
                else 
                {
                    //Creating a ContentType object to validate the content type string.
                    //Can replace this later with a static method to validate the content type.
                    SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType, new ContentType(value).ToString()); 
                }
            } 
        } 

        ///  
        /// The primary language of the package content. The language tag is
        /// composed of one or more parts: A primary language subtag and a
        /// (possibly empty) series of subsequent subtags, for example, "EN-US".
        /// These values MUST follow the convention specified in RFC 3066. 
        /// 
        public override string Language 
        { 
            get
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Language) as string;
            }

            set 
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Language, value); 
            } 
        }
 
        /// 
        /// The version number. This value is set by the user or by the application.
        /// 
        public override string Version 
        {
            get 
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Version) as string;
            } 

            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Version, value); 
            }
        } 
 
        /// 
        /// The status of the content. Example values include "Draft", 
        /// "Reviewed", and "Final".
        /// 
        public override string ContentStatus
        { 
            get
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentStatus) as string; 
            }
 
            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentStatus, value);
            } 
        }
 
        #endregion DocumentSummaryInformation properties 

        //------------------------------------------------------ 
        //
        //  IDisposable Methods
        //
        //------------------------------------------------------ 

        #region IDisposable 
 
        /// 
        /// Dispose(bool disposing) executes in two distinct scenarios. 
        /// If disposing equals true, the method has been called directly
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed.
        /// 
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference 
        /// other objects. Only unmanaged resources can be disposed. 
        /// 
        ///  
        /// true if called from Dispose(); false if called from the finalizer.
        /// 
        protected override void
        Dispose( 
            bool disposing
            ) 
        { 
            try
            { 
                if (!_disposed && disposing)
                {
                    if (_psSummInfo != null)
                    { 
                        try
                        { 
                            ((IDisposable)_psSummInfo).Dispose(); 
                        }
                        finally 
                        {
                            _psSummInfo = null;
                        }
                    } 

                    if (_psDocSummInfo != null) 
                    { 
                        try
                        { 
                            ((IDisposable)_psDocSummInfo).Dispose();
                        }
                        finally
                        { 
                            _psDocSummInfo = null;
                        } 
                    } 
                }
            } 
            finally
            {
                //
                // By setting _disposed = true, we ensure that all future accesses to 
                // this object will fail (because both GetOleProperty and SetOleProperty
                // call CheckDisposed). Note that we wrap the entire body of 
                // Dispose(bool) (this method) in an "if (!_disposed)". 
                // And we also set each reference to null immediately after attempting
                // to release it. So we never attempt to release any reference more 
                // than once.
                //
                _disposed = true;
                base.Dispose(disposing); 
            }
        } 
 
        #endregion IDisposable
 
        #endregion Public Properties

        //-----------------------------------------------------
        // 
        //  Private Methods
        // 
        //------------------------------------------------------ 

        #region Private Methods 

        /// 
        /// Obtain the specified property from the specified property set.
        ///  
        /// 
        /// "Format identifier" that specifies the property set from which to 
        /// obtain the property. 
        /// 
        ///  
        /// Identifier of the property to obtain.
        /// 
        /// 
        /// An object of the appropriate type for the specified property which 
        /// contains the property value, or null if the property does not exist
        /// in the encrypted package. 
        ///  
        ///
        ///     Critical: calls Marshal.PtrToStringAnsi which LinkDemands 
        ///     TreatAsSafe: can't be used to allocate a string from an arbitrary pointer since it doesn't accept a ptr.
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private object 
        GetOleProperty(
            Guid fmtid, 
            uint propId 
            )
        { 
            CheckDisposed();

            // fmtid is always either DocSum or Sum.
            IPropertyStorage ps = 
                fmtid == FormatId.SummaryInformation ? _psSummInfo : _psDocSummInfo;
            if (ps == null) 
            { 
                // This file doesn't even contain the property storage that this
                // property belongs to, so it certainly doesn't contain the property. 
                return null;
            }

            object obj = null; 

            PROPSPEC[] propSpecs = new PROPSPEC[1]; 
            PROPVARIANT[] vals = new PROPVARIANT[1]; 

            propSpecs[0].propType = (uint)PropSpecType.Id; 
            propSpecs[0].union.propId = propId;

            VARTYPE vtExpected = GetVtFromPropId(fmtid, propId);
 
            int hresult = ps.ReadMultiple(1, propSpecs, vals);
 
            if (hresult == SafeNativeCompoundFileConstants.S_OK) 
            {
                try 
                {
                    if (vals[0].vt != vtExpected)
                    {
                        throw new FileFormatException( 
                                        SR.Get(
                                            SRID.WrongDocumentPropertyVariantType, 
                                            propId, 
                                            fmtid.ToString(),
                                            vals[0].vt, 
                                            vtExpected
                                            )
                                        );
                    } 

                    switch (vals[0].vt) 
                    { 
                        case VARTYPE.VT_LPSTR:
                            // 
                            // We store string properties as CP_ACP or UTF-8.
                            // But no matter which format the string was encoded, we always use the UTF-8
                            // encoder/decoder to decode the byte array, because the UTF-8 code of an ASCII
                            // string is the same as the ASCII string. 
                            //
                            IntPtr pszVal = vals[0].union.pszVal; 
                            // 
                            // Because both the ASCII string and UTF-8 encoded string (byte array) are
                            // stored in a memory block (pszVal) terminated by null, we can use 
                            // Marshal.PtrToStringAnsi(pszVal) to convert the memory block pointed by
                            // pszVal to a string. Then from the string.Length, we can get the number of
                            // bytes in the memory block. Otherwise, we cannot easily tell how many bytes
                            // are stored in pszVal without an extra parameter. 
                            //
                            string ansiString = Marshal.PtrToStringAnsi(pszVal); 
                            int nLen = ansiString.Length; 

                            byte[] byteArray = new byte[nLen]; 
                            Marshal.Copy(pszVal, byteArray, 0, nLen);

                            obj = UTF8Encoding.UTF8.GetString(byteArray);
                            break; 

                        case VARTYPE.VT_FILETIME: 
                            // 
                            // DateTime doesn't have a conversion from FILETIME. It has a
                            // misleadingly named "FromFileTime" method that actually wants 
                            // a long. So...
                            //
                            obj = new Nullable(DateTime.FromFileTime(vals[0].union.hVal));
                            break; 

                        default: 
                            throw new FileFormatException( 
                                        SR.Get(SRID.InvalidDocumentPropertyVariantType, vals[0].vt));
                    } 
                }
                finally
                {
#pragma warning suppress 6031 // suppressing a "by design" ignored return value 
                    SafeNativeCompoundFileMethods.SafePropVariantClear(ref vals[0]);
                } 
            } 
            else if (hresult == SafeNativeCompoundFileConstants.S_FALSE)
            { 
                // Do nothing -- return the null object reference.
            }
            else
            { 
                SecurityHelper.ThrowExceptionForHR(hresult);
            } 
 
            return obj;
        } 

        /// 
        /// Set or delete the specified property in the specified property set.
        ///  
        /// 
        /// "Format identifier" that specifies the property set in which to 
        /// set the property. 
        /// 
        ///  
        /// Identifier of the property to set.
        /// 
        /// 
        /// An object of the appropriate type for the specified property which 
        /// contains the property value, or null if the property is to be deleted.
        ///  
        /// 
        ///     Critical: Calls Marshal.StringToCoTaskMemAnsi which LinkDemands.  Also has unsafe code block.
        ///     TreatAsSafe: the memory that's allocated is freed before returning.  Unsafe code block only manipulates local memory on the stack. 
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void
        SetOleProperty( 
            Guid fmtid,
            uint propId, 
            object propVal 
            )
        { 
            CheckDisposed();

            IPropertyStorage ps =
                fmtid == FormatId.SummaryInformation ? _psSummInfo : _psDocSummInfo; 

            if (ps == null) 
            { 
                //
                // The property set does not exist, so create it. 
                //
                if (propVal != null)
                {
                    _pss.Create( 
                            ref fmtid,
                            ref fmtid, 
                            SafeNativeCompoundFileConstants.PROPSETFLAG_ANSI, 
                            (uint)_grfMode,
                            out ps 
                            );
                    if (fmtid == FormatId.SummaryInformation)
                    {
                        _psSummInfo = ps; 
                    }
                    else 
                    { 
                        _psDocSummInfo = ps;
                    } 
                }
                else
                {
                    // 
                    // But if we were going to delete the property anyway, there's
                    // nothing to do. 
                    // 
                    return;
                } 
            }

            PROPSPEC[] propSpecs = new PROPSPEC[1];
            PROPVARIANT[] vals = new PROPVARIANT[1]; 

            propSpecs[0].propType = (uint)PropSpecType.Id; 
            propSpecs[0].union.propId = propId; 

            if (propVal == null) 
            {
                //
                // New value is null => remove the property. Unlike in the case of ReadMultiple,
                // we can just let this one throw an exception on failure. There are no non-zero 
                // success codes to worry about.
                // 
                ps.DeleteMultiple(1, propSpecs); 
                return;
            } 

            //
            // New value is non-null => set a new value for the property.
            // 
            IntPtr pszVal = IntPtr.Zero;
            try 
            { 
                if (propVal is string)
                { 
                    //
                    // 1) We store string properties internally as UTF-16.
                    //    During save, convert the string (UTF-16) to CP_ACP and back
                    // 2) If property value changed during that process, store it in CF OLE Storage as UTF-8 
                    // 3) Otherwise store it as CP_ACP
                    // 
                    string inputString = propVal as string; 

                    pszVal = Marshal.StringToCoTaskMemAnsi(inputString); 
                    string convertedString = Marshal.PtrToStringAnsi(pszVal);

                    if (String.CompareOrdinal(inputString, convertedString) != 0)
                    { 
                        // The string is not an ASCII string. Use UTF-8 to encode it!
                        byte[] byteArray = UTF8Encoding.UTF8.GetBytes(inputString); 
                        int nLen = byteArray.Length; 

                        // 
                        // Before memory allocation for holding UTF-8 codes, we need to first free the memory
                        // allocated by Marshal.StringToCoTaskMemAnsi().
                        // Note that if there is any exception in this try scope, the memory will still be released
                        // by the finally of this try scope. 
                        //
                        if (pszVal != IntPtr.Zero) 
                        { 
                            Marshal.FreeCoTaskMem(pszVal);
                            pszVal = IntPtr.Zero; 
                        }

                        pszVal = Marshal.AllocCoTaskMem(checked(nLen + 1));  //The extra one byte is for the string terminator null.
 
                        Marshal.Copy(byteArray, 0, pszVal, nLen);
                        Marshal.WriteByte(pszVal, nLen, 0);     //Put the string terminator null at the end of the array. 
                    } 

                    vals[0].vt = VARTYPE.VT_LPSTR; 
                    vals[0].union.pszVal = pszVal;
                }
                else if (propVal is DateTime)
                { 
                    // set FileTime as an Int64 to avoid pointer operations
                    vals[0].vt = VARTYPE.VT_FILETIME; 
                    vals[0].union.hVal = ((DateTime)propVal).ToFileTime(); 
                }
                else 
                {
                    throw new ArgumentException(
                                SR.Get(SRID.InvalidDocumentPropertyType, propVal.GetType().ToString()),
                                "propVal"); 
                }
 
                // 
                // Again, we can just let it throw on failure; no non-zero success codes. It won't throw
                // if the property doesn't exist. 
                //
                ps.WriteMultiple(1, propSpecs, vals, 0);
            }
            finally 
            {
                if (pszVal != IntPtr.Zero) 
                { 
                    Marshal.FreeCoTaskMem(pszVal);
                } 
            }
        }

        ///  
        /// Obtain the specified nullable DateTime property from the specified property set. Since nullable DateTime
        /// is a struct, the "null" case (when the property is absent) must be treated specially. 
        ///  
        /// 
        /// "Format identifier" that specifies the property set from which to obtain the property. 
        /// 
        /// 
        /// Identifier of the property to obtain.
        ///  
        /// 
        /// A nullable DateTime structure representing the specified property. Note that a Generic Nullable 
        /// struct can be compared successfully to null. 
        /// 
        private Nullable 
        GetDateTimeProperty(
            Guid fmtid,
            uint propId
            ) 
        {
            object obj = GetOleProperty(fmtid, propId); 
            return obj != null ? (Nullable)obj : new Nullable(); 
        }
 
        private void
        OpenPropertyStorage(
            ref Guid fmtid,
            out IPropertyStorage ips 
            )
        { 
            int hr = _pss.Open(ref fmtid, (uint)_grfMode, out ips); 

            // 
            // A COM "not found" error is acceptable; it just means that the
            // file doesn't have the requested property set. Any other COM error code
            // is an error.
            // 
            if (hr == SafeNativeCompoundFileConstants.STG_E_FILENOTFOUND)
            { 
                ips = null; // Just for safety; the failed call to Open should have set it to null. 
            }
            else 
            {
                // Throw if we failed.
                SecurityHelper.ThrowExceptionForHR(hr);
            } 
        }
 
        private VARTYPE 
        GetVtFromPropId(
            Guid fmtid, 
            uint propId
            )
        {
            if (fmtid == FormatId.SummaryInformation) 
            {
                switch (propId) 
                { 
                    case PropertyId.Title:
                    case PropertyId.Subject: 
                    case PropertyId.Creator:
                    case PropertyId.Keywords:
                    case PropertyId.Description:
                    case PropertyId.LastModifiedBy: 
                    case PropertyId.Revision:
                        return VARTYPE.VT_LPSTR; 
 
                    case PropertyId.LastPrinted:
                    case PropertyId.DateCreated: 
                    case PropertyId.DateModified:
                        return VARTYPE.VT_FILETIME;

                    default: 
                        throw new ArgumentException(
                            SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                            "propId" 
                            );
                } 
            }
            else if (fmtid == FormatId.DocumentSummaryInformation)
            {
                switch (propId) 
                {
                    case PropertyId.Category: 
                    case PropertyId.Identifier: 
                    case PropertyId.ContentType:
                    case PropertyId.Language: 
                    case PropertyId.Version:
                    case PropertyId.ContentStatus:
                        return VARTYPE.VT_LPSTR;
 
                    default:
                        throw new ArgumentException( 
                            SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                            "propId"
                            ); 
                }
            }
            else
            { 
                throw new ArgumentException(
                    SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                    "fmtid" 
                    );
            } 
        }

        private void
        CheckDisposed() 
        {
            if (_disposed) 
                throw new ObjectDisposedException(null, SR.Get(SRID.StorageBasedPackagePropertiesDiposed)); 
        }
 
        #endregion Private Methods

        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private bool _disposed;

        private int _grfMode;  // Mode in which the compound file was opened. 

        // 
        // Interface to the OLE property sets in the compound file representing 
        // the RM-protected OPC package.
        // 
        private IPropertySetStorage _pss;
        private IPropertyStorage _psSummInfo;
        private IPropertyStorage _psDocSummInfo;
 
        #endregion Private Fields
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//  This class provides access to the package properties of an RM-protected OPC 
//  document. The "package properties" are a subset of the standard OLE property
//  sets SummaryInformation and DocumentSummaryInformation, and include such 
//  properties as Title and Subject.
//
//  An RM-protected OPC document is physically represented by an OLE compound
//  file containing a well-known stream in which an OPC Zip archive, encrypted 
//  in its entirety, is stored. The package properties of an RM-protected OPC
//  document are stored in the standard OLE compound file property set streams, 
//  \005SummaryInformation and \005DocumentSummaryInformation. The contents of 
//  these streams is intended to mirror the corresponding metadata properties
//  stored in the OPC package itself. These properties are duplicated, in the 
//  clear, outside of the encrypted OPC package stream, so that tools such as
//  the Shell can display the properties without having to decrypt the package.
//
//  It is the responsibility of the application to ensure that the properties in 
//  the OLE property set streams are synchronized with the properties in the
//  OPC package. 
// 
// History:
//  06/16/2005: LGolding:   Initial implementation. 
//  09/23/2005: JohnLarc:   Removed from public surface.
//
//-----------------------------------------------------------------------------
 
using System;
using System.IO; 
using System.IO.Packaging; 
using System.Runtime.InteropServices;
using System.Windows; 
using System.Security; // SecurityCritical
using System.Text;      //For UTF-8 encoding.

using MS.Internal; 
using MS.Internal.Interop;
using MS.Internal.IO.Packaging.CompoundFile; 
using MS.Internal.WindowsBase;  //for SecurityHelper. 

// Enable presharp pragma warning suppress directives. 
#pragma warning disable 1634, 1691

namespace MS.Internal.IO.Packaging
{ 
    /// 
    /// This class provides access to the package properties, such as Title and 
    /// Subject, of an RM-protected OPC package. These properties are a subset of 
    /// of the standard OLE property sets SummaryInformation and
    /// DocumentSummaryInformation. 
    /// 
    internal class StorageBasedPackageProperties : PackageProperties, IDisposable
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors

        //
        // The constructor is internal because an application never directly 
        // creates an object of this class. An application obtains an object
        // of this class through the PackageProperties CLR property of the 
        // EncryptedPackageEnvelope class: 
        //
        //      EncryptedPackageEnvelope ep = EncryptedPackageEnvelope.Create("mydoc.xps", ...); 
        //      PackageProperties props = ep.PackageProperties;
        //
        internal
        StorageBasedPackageProperties( 
            StorageRoot root
            ) 
        { 
            _pss = (IPropertySetStorage)root.GetRootIStorage();
 
            //
            // Open the property sets with the same access with which the file itself
            // was opened.
            // 
            _grfMode = SafeNativeCompoundFileConstants.STGM_DIRECT
                        | SafeNativeCompoundFileConstants.STGM_SHARE_EXCLUSIVE; 
            SafeNativeCompoundFileMethods.UpdateModeFlagFromFileAccess(root.OpenAccess, ref _grfMode); 

            OpenPropertyStorage(ref FormatId.SummaryInformation, out _psSummInfo); 
            OpenPropertyStorage(ref FormatId.DocumentSummaryInformation, out _psDocSummInfo);
        }

        ///  
        /// Finalizer.
        ///  
        ~StorageBasedPackageProperties() 
        {
            Dispose(false); 
        }

        #endregion Constructors
 
        //------------------------------------------------------
        // 
        //  Public Properties 
        //
        //----------------------------------------------------- 

        #region Public Properties

        #region SummaryInformation properties 

        ///  
        /// The title. 
        /// 
        public override string Title 
        {
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Title) as string; 
            }
 
            set 
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Title, value); 
            }
        }

        ///  
        /// The topic of the contents.
        ///  
        public override string Subject 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Subject) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Subject, value); 
            }
        } 

        /// 
        /// The primary creator. The identification is environment-specific and
        /// can consist of a name, email address, employee ID, etc. It is 
        /// recommended that this value be only as verbose as necessary to
        /// identify the individual. 
        ///  
        public override string Creator
        { 
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Creator) as string;
            } 

            set 
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Creator, value);
            } 
        }

        /// 
        /// A delimited set of keywords to support searching and indexing. This 
        /// is typically a list of terms that are not available elsewhere in the
        /// properties. 
        ///  
        public override string Keywords
        { 
            get
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Keywords) as string;
            } 

            set 
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Keywords, value);
            } 
        }

        /// 
        /// The description or abstract of the contents. 
        /// 
        public override string Description 
        { 
            get
            { 
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Description) as string;
            }

            set 
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Description, value); 
            } 
        }
 
        /// 
        /// The user who performed the last modification. The identification is
        /// environment-specific and can consist of a name, email address,
        /// employee ID, etc. It is recommended that this value be only as 
        /// verbose as necessary to identify the individual.
        ///  
        public override string LastModifiedBy 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.LastModifiedBy) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.LastModifiedBy, value); 
            }
        } 

        /// 
        /// The revision number. This value indicates the number of saves or
        /// revisions. The application is responsible for updating this value 
        /// after each revision.
        ///  
        public override string Revision 
        {
            get 
            {
                return GetOleProperty(FormatId.SummaryInformation, PropertyId.Revision) as string;
            }
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.Revision, value); 
            }
        } 

        /// 
        /// The date and time of the last printing.
        ///  
        public override Nullable LastPrinted
        { 
            get 
            {
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.LastPrinted); 
            }

            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.LastPrinted, value);
            } 
        } 

        ///  
        /// The creation date and time.
        /// 
        public override Nullable Created
        { 
            get
            { 
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.DateCreated); 
            }
 
            set
            {
                SetOleProperty(FormatId.SummaryInformation, PropertyId.DateCreated, value);
            } 
        }
 
        ///  
        /// The date and time of the last modification.
        ///  
        public override Nullable Modified
        {
            get
            { 
                return GetDateTimeProperty(FormatId.SummaryInformation, PropertyId.DateModified);
            } 
 
            set
            { 
                SetOleProperty(FormatId.SummaryInformation, PropertyId.DateModified, value);
            }
        }
 
        #endregion SummaryInformation properties
 
        #region DocumentSummaryInformation properties 

        ///  
        /// The category. This value is typically used by UI applications to create navigation
        /// controls.
        /// 
        public override string Category 
        {
            get 
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Category) as string;
            } 

            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Category, value); 
            }
        } 
 
        /// 
        /// A unique identifier. 
        /// 
        public override string Identifier
        {
            get 
            {
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Identifier) as string; 
            } 

            set 
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Identifier, value);
            }
        } 

        ///  
        /// The type of content represented, generally defined by a specific 
        /// use and intended audience. Example values include "Whitepaper"
        /// and "Exam". (This property is distinct from 
        /// MIME content types as defined in RFC 2045.)
        /// 
        public override string ContentType
        { 
            get
            { 
                string contentType = GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType) as string; 
                if (contentType == null)
                { 
                    return contentType;
                }
                else
                { 
                    //Creating a ContentType object to validate the content type string.
                    //Can replace this later with a static method to validate the content type. 
                    return new ContentType(contentType).ToString(); 
                }
            } 

            set
            {
                if (value == null) 
                {
                    //indicates that the property should be deleted. 
                    SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType, value); 
                }
                else 
                {
                    //Creating a ContentType object to validate the content type string.
                    //Can replace this later with a static method to validate the content type.
                    SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentType, new ContentType(value).ToString()); 
                }
            } 
        } 

        ///  
        /// The primary language of the package content. The language tag is
        /// composed of one or more parts: A primary language subtag and a
        /// (possibly empty) series of subsequent subtags, for example, "EN-US".
        /// These values MUST follow the convention specified in RFC 3066. 
        /// 
        public override string Language 
        { 
            get
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Language) as string;
            }

            set 
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Language, value); 
            } 
        }
 
        /// 
        /// The version number. This value is set by the user or by the application.
        /// 
        public override string Version 
        {
            get 
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Version) as string;
            } 

            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.Version, value); 
            }
        } 
 
        /// 
        /// The status of the content. Example values include "Draft", 
        /// "Reviewed", and "Final".
        /// 
        public override string ContentStatus
        { 
            get
            { 
                return GetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentStatus) as string; 
            }
 
            set
            {
                SetOleProperty(FormatId.DocumentSummaryInformation, PropertyId.ContentStatus, value);
            } 
        }
 
        #endregion DocumentSummaryInformation properties 

        //------------------------------------------------------ 
        //
        //  IDisposable Methods
        //
        //------------------------------------------------------ 

        #region IDisposable 
 
        /// 
        /// Dispose(bool disposing) executes in two distinct scenarios. 
        /// If disposing equals true, the method has been called directly
        /// or indirectly by a user's code. Managed and unmanaged resources
        /// can be disposed.
        /// 
        /// If disposing equals false, the method has been called by the
        /// runtime from inside the finalizer and you should not reference 
        /// other objects. Only unmanaged resources can be disposed. 
        /// 
        ///  
        /// true if called from Dispose(); false if called from the finalizer.
        /// 
        protected override void
        Dispose( 
            bool disposing
            ) 
        { 
            try
            { 
                if (!_disposed && disposing)
                {
                    if (_psSummInfo != null)
                    { 
                        try
                        { 
                            ((IDisposable)_psSummInfo).Dispose(); 
                        }
                        finally 
                        {
                            _psSummInfo = null;
                        }
                    } 

                    if (_psDocSummInfo != null) 
                    { 
                        try
                        { 
                            ((IDisposable)_psDocSummInfo).Dispose();
                        }
                        finally
                        { 
                            _psDocSummInfo = null;
                        } 
                    } 
                }
            } 
            finally
            {
                //
                // By setting _disposed = true, we ensure that all future accesses to 
                // this object will fail (because both GetOleProperty and SetOleProperty
                // call CheckDisposed). Note that we wrap the entire body of 
                // Dispose(bool) (this method) in an "if (!_disposed)". 
                // And we also set each reference to null immediately after attempting
                // to release it. So we never attempt to release any reference more 
                // than once.
                //
                _disposed = true;
                base.Dispose(disposing); 
            }
        } 
 
        #endregion IDisposable
 
        #endregion Public Properties

        //-----------------------------------------------------
        // 
        //  Private Methods
        // 
        //------------------------------------------------------ 

        #region Private Methods 

        /// 
        /// Obtain the specified property from the specified property set.
        ///  
        /// 
        /// "Format identifier" that specifies the property set from which to 
        /// obtain the property. 
        /// 
        ///  
        /// Identifier of the property to obtain.
        /// 
        /// 
        /// An object of the appropriate type for the specified property which 
        /// contains the property value, or null if the property does not exist
        /// in the encrypted package. 
        ///  
        ///
        ///     Critical: calls Marshal.PtrToStringAnsi which LinkDemands 
        ///     TreatAsSafe: can't be used to allocate a string from an arbitrary pointer since it doesn't accept a ptr.
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private object 
        GetOleProperty(
            Guid fmtid, 
            uint propId 
            )
        { 
            CheckDisposed();

            // fmtid is always either DocSum or Sum.
            IPropertyStorage ps = 
                fmtid == FormatId.SummaryInformation ? _psSummInfo : _psDocSummInfo;
            if (ps == null) 
            { 
                // This file doesn't even contain the property storage that this
                // property belongs to, so it certainly doesn't contain the property. 
                return null;
            }

            object obj = null; 

            PROPSPEC[] propSpecs = new PROPSPEC[1]; 
            PROPVARIANT[] vals = new PROPVARIANT[1]; 

            propSpecs[0].propType = (uint)PropSpecType.Id; 
            propSpecs[0].union.propId = propId;

            VARTYPE vtExpected = GetVtFromPropId(fmtid, propId);
 
            int hresult = ps.ReadMultiple(1, propSpecs, vals);
 
            if (hresult == SafeNativeCompoundFileConstants.S_OK) 
            {
                try 
                {
                    if (vals[0].vt != vtExpected)
                    {
                        throw new FileFormatException( 
                                        SR.Get(
                                            SRID.WrongDocumentPropertyVariantType, 
                                            propId, 
                                            fmtid.ToString(),
                                            vals[0].vt, 
                                            vtExpected
                                            )
                                        );
                    } 

                    switch (vals[0].vt) 
                    { 
                        case VARTYPE.VT_LPSTR:
                            // 
                            // We store string properties as CP_ACP or UTF-8.
                            // But no matter which format the string was encoded, we always use the UTF-8
                            // encoder/decoder to decode the byte array, because the UTF-8 code of an ASCII
                            // string is the same as the ASCII string. 
                            //
                            IntPtr pszVal = vals[0].union.pszVal; 
                            // 
                            // Because both the ASCII string and UTF-8 encoded string (byte array) are
                            // stored in a memory block (pszVal) terminated by null, we can use 
                            // Marshal.PtrToStringAnsi(pszVal) to convert the memory block pointed by
                            // pszVal to a string. Then from the string.Length, we can get the number of
                            // bytes in the memory block. Otherwise, we cannot easily tell how many bytes
                            // are stored in pszVal without an extra parameter. 
                            //
                            string ansiString = Marshal.PtrToStringAnsi(pszVal); 
                            int nLen = ansiString.Length; 

                            byte[] byteArray = new byte[nLen]; 
                            Marshal.Copy(pszVal, byteArray, 0, nLen);

                            obj = UTF8Encoding.UTF8.GetString(byteArray);
                            break; 

                        case VARTYPE.VT_FILETIME: 
                            // 
                            // DateTime doesn't have a conversion from FILETIME. It has a
                            // misleadingly named "FromFileTime" method that actually wants 
                            // a long. So...
                            //
                            obj = new Nullable(DateTime.FromFileTime(vals[0].union.hVal));
                            break; 

                        default: 
                            throw new FileFormatException( 
                                        SR.Get(SRID.InvalidDocumentPropertyVariantType, vals[0].vt));
                    } 
                }
                finally
                {
#pragma warning suppress 6031 // suppressing a "by design" ignored return value 
                    SafeNativeCompoundFileMethods.SafePropVariantClear(ref vals[0]);
                } 
            } 
            else if (hresult == SafeNativeCompoundFileConstants.S_FALSE)
            { 
                // Do nothing -- return the null object reference.
            }
            else
            { 
                SecurityHelper.ThrowExceptionForHR(hresult);
            } 
 
            return obj;
        } 

        /// 
        /// Set or delete the specified property in the specified property set.
        ///  
        /// 
        /// "Format identifier" that specifies the property set in which to 
        /// set the property. 
        /// 
        ///  
        /// Identifier of the property to set.
        /// 
        /// 
        /// An object of the appropriate type for the specified property which 
        /// contains the property value, or null if the property is to be deleted.
        ///  
        /// 
        ///     Critical: Calls Marshal.StringToCoTaskMemAnsi which LinkDemands.  Also has unsafe code block.
        ///     TreatAsSafe: the memory that's allocated is freed before returning.  Unsafe code block only manipulates local memory on the stack. 
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void
        SetOleProperty( 
            Guid fmtid,
            uint propId, 
            object propVal 
            )
        { 
            CheckDisposed();

            IPropertyStorage ps =
                fmtid == FormatId.SummaryInformation ? _psSummInfo : _psDocSummInfo; 

            if (ps == null) 
            { 
                //
                // The property set does not exist, so create it. 
                //
                if (propVal != null)
                {
                    _pss.Create( 
                            ref fmtid,
                            ref fmtid, 
                            SafeNativeCompoundFileConstants.PROPSETFLAG_ANSI, 
                            (uint)_grfMode,
                            out ps 
                            );
                    if (fmtid == FormatId.SummaryInformation)
                    {
                        _psSummInfo = ps; 
                    }
                    else 
                    { 
                        _psDocSummInfo = ps;
                    } 
                }
                else
                {
                    // 
                    // But if we were going to delete the property anyway, there's
                    // nothing to do. 
                    // 
                    return;
                } 
            }

            PROPSPEC[] propSpecs = new PROPSPEC[1];
            PROPVARIANT[] vals = new PROPVARIANT[1]; 

            propSpecs[0].propType = (uint)PropSpecType.Id; 
            propSpecs[0].union.propId = propId; 

            if (propVal == null) 
            {
                //
                // New value is null => remove the property. Unlike in the case of ReadMultiple,
                // we can just let this one throw an exception on failure. There are no non-zero 
                // success codes to worry about.
                // 
                ps.DeleteMultiple(1, propSpecs); 
                return;
            } 

            //
            // New value is non-null => set a new value for the property.
            // 
            IntPtr pszVal = IntPtr.Zero;
            try 
            { 
                if (propVal is string)
                { 
                    //
                    // 1) We store string properties internally as UTF-16.
                    //    During save, convert the string (UTF-16) to CP_ACP and back
                    // 2) If property value changed during that process, store it in CF OLE Storage as UTF-8 
                    // 3) Otherwise store it as CP_ACP
                    // 
                    string inputString = propVal as string; 

                    pszVal = Marshal.StringToCoTaskMemAnsi(inputString); 
                    string convertedString = Marshal.PtrToStringAnsi(pszVal);

                    if (String.CompareOrdinal(inputString, convertedString) != 0)
                    { 
                        // The string is not an ASCII string. Use UTF-8 to encode it!
                        byte[] byteArray = UTF8Encoding.UTF8.GetBytes(inputString); 
                        int nLen = byteArray.Length; 

                        // 
                        // Before memory allocation for holding UTF-8 codes, we need to first free the memory
                        // allocated by Marshal.StringToCoTaskMemAnsi().
                        // Note that if there is any exception in this try scope, the memory will still be released
                        // by the finally of this try scope. 
                        //
                        if (pszVal != IntPtr.Zero) 
                        { 
                            Marshal.FreeCoTaskMem(pszVal);
                            pszVal = IntPtr.Zero; 
                        }

                        pszVal = Marshal.AllocCoTaskMem(checked(nLen + 1));  //The extra one byte is for the string terminator null.
 
                        Marshal.Copy(byteArray, 0, pszVal, nLen);
                        Marshal.WriteByte(pszVal, nLen, 0);     //Put the string terminator null at the end of the array. 
                    } 

                    vals[0].vt = VARTYPE.VT_LPSTR; 
                    vals[0].union.pszVal = pszVal;
                }
                else if (propVal is DateTime)
                { 
                    // set FileTime as an Int64 to avoid pointer operations
                    vals[0].vt = VARTYPE.VT_FILETIME; 
                    vals[0].union.hVal = ((DateTime)propVal).ToFileTime(); 
                }
                else 
                {
                    throw new ArgumentException(
                                SR.Get(SRID.InvalidDocumentPropertyType, propVal.GetType().ToString()),
                                "propVal"); 
                }
 
                // 
                // Again, we can just let it throw on failure; no non-zero success codes. It won't throw
                // if the property doesn't exist. 
                //
                ps.WriteMultiple(1, propSpecs, vals, 0);
            }
            finally 
            {
                if (pszVal != IntPtr.Zero) 
                { 
                    Marshal.FreeCoTaskMem(pszVal);
                } 
            }
        }

        ///  
        /// Obtain the specified nullable DateTime property from the specified property set. Since nullable DateTime
        /// is a struct, the "null" case (when the property is absent) must be treated specially. 
        ///  
        /// 
        /// "Format identifier" that specifies the property set from which to obtain the property. 
        /// 
        /// 
        /// Identifier of the property to obtain.
        ///  
        /// 
        /// A nullable DateTime structure representing the specified property. Note that a Generic Nullable 
        /// struct can be compared successfully to null. 
        /// 
        private Nullable 
        GetDateTimeProperty(
            Guid fmtid,
            uint propId
            ) 
        {
            object obj = GetOleProperty(fmtid, propId); 
            return obj != null ? (Nullable)obj : new Nullable(); 
        }
 
        private void
        OpenPropertyStorage(
            ref Guid fmtid,
            out IPropertyStorage ips 
            )
        { 
            int hr = _pss.Open(ref fmtid, (uint)_grfMode, out ips); 

            // 
            // A COM "not found" error is acceptable; it just means that the
            // file doesn't have the requested property set. Any other COM error code
            // is an error.
            // 
            if (hr == SafeNativeCompoundFileConstants.STG_E_FILENOTFOUND)
            { 
                ips = null; // Just for safety; the failed call to Open should have set it to null. 
            }
            else 
            {
                // Throw if we failed.
                SecurityHelper.ThrowExceptionForHR(hr);
            } 
        }
 
        private VARTYPE 
        GetVtFromPropId(
            Guid fmtid, 
            uint propId
            )
        {
            if (fmtid == FormatId.SummaryInformation) 
            {
                switch (propId) 
                { 
                    case PropertyId.Title:
                    case PropertyId.Subject: 
                    case PropertyId.Creator:
                    case PropertyId.Keywords:
                    case PropertyId.Description:
                    case PropertyId.LastModifiedBy: 
                    case PropertyId.Revision:
                        return VARTYPE.VT_LPSTR; 
 
                    case PropertyId.LastPrinted:
                    case PropertyId.DateCreated: 
                    case PropertyId.DateModified:
                        return VARTYPE.VT_FILETIME;

                    default: 
                        throw new ArgumentException(
                            SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                            "propId" 
                            );
                } 
            }
            else if (fmtid == FormatId.DocumentSummaryInformation)
            {
                switch (propId) 
                {
                    case PropertyId.Category: 
                    case PropertyId.Identifier: 
                    case PropertyId.ContentType:
                    case PropertyId.Language: 
                    case PropertyId.Version:
                    case PropertyId.ContentStatus:
                        return VARTYPE.VT_LPSTR;
 
                    default:
                        throw new ArgumentException( 
                            SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                            "propId"
                            ); 
                }
            }
            else
            { 
                throw new ArgumentException(
                    SR.Get(SRID.UnknownDocumentProperty, fmtid.ToString(), propId), 
                    "fmtid" 
                    );
            } 
        }

        private void
        CheckDisposed() 
        {
            if (_disposed) 
                throw new ObjectDisposedException(null, SR.Get(SRID.StorageBasedPackagePropertiesDiposed)); 
        }
 
        #endregion Private Methods

        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        private bool _disposed;

        private int _grfMode;  // Mode in which the compound file was opened. 

        // 
        // Interface to the OLE property sets in the compound file representing 
        // the RM-protected OPC package.
        // 
        private IPropertySetStorage _pss;
        private IPropertyStorage _psSummInfo;
        private IPropertyStorage _psDocSummInfo;
 
        #endregion Private Fields
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK