internal ManagedPropSpec(PROPSPEC propSpec) { SecurityHelper.DemandUnmanagedCode(); PropSpecType propType = (PropSpecType)propSpec.propType; if (propType == PropSpecType.Name) { this.PropName = Marshal.PtrToStringUni(propSpec.union.name); return; } if (propType == PropSpecType.Id) { this.PropId = propSpec.union.propId; return; } throw new ArgumentException(SR.Get("FilterPropSpecUnknownUnionSelector"), "propSpec"); }
internal static void MarshalPropSpec(ManagedPropSpec propSpec, ref PROPSPEC native) { native.propType = (uint)propSpec.PropType; PropSpecType propType = propSpec.PropType; if (propType == PropSpecType.Name) { native.union.name = Marshal.StringToCoTaskMemUni(propSpec.PropName); return; } if (propType == PropSpecType.Id) { native.union.propId = propSpec.PropId; return; } Invariant.Assert(false); }
/// <summary> /// Marshal Managed to Native PROPSPEC /// </summary> /// <param name="propSpec"></param> /// <param name="native"></param> internal static void MarshalPropSpec(ManagedPropSpec propSpec, ref PROPSPEC native) { native.propType = (uint)propSpec.PropType; switch (propSpec.PropType) { case PropSpecType.Id: native.union.propId = (uint)propSpec.PropId; break; case PropSpecType.Name: native.union.name = Marshal.StringToCoTaskMemUni(propSpec.PropName); break; default: Invariant.Assert(false); // propSpec.PropType is set by internal code in the filter logic. break; } }
/// <summary> /// Create a ManagedPropSpec from an unmanaged one /// </summary> internal ManagedPropSpec(PROPSPEC propSpec) { // Assign to properties rather than fields to ensure consistency through side-effects. switch ((PropSpecType)propSpec.propType) { case PropSpecType.Id: { PropId = propSpec.union.propId; break; } case PropSpecType.Name: { PropName = Marshal.PtrToStringUni(propSpec.union.name); break; } default: throw new ArgumentException(SR.Get(SRID.FilterPropSpecUnknownUnionSelector), "propSpec"); } }
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); } } }
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>(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); }
internal static void MarshalPropSpec(ManagedPropSpec propSpec, ref PROPSPEC native) { native.propType = (uint)propSpec.PropType; switch (propSpec.PropType) { case PropSpecType.Id: native.union.propId = (uint)propSpec.PropId; break; case PropSpecType.Name: native.union.name = Marshal.StringToCoTaskMemUni(propSpec.PropName); break; default: Invariant.Assert(false); // propSpec.PropType is set by internal code in the filter logic. break; } }
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); } } }
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>(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; }
internal ManagedPropSpec(PROPSPEC propSpec) { SecurityHelper.DemandUnmanagedCode(); // Assign to properties rather than fields to ensure consistency through side-effects. switch ((PropSpecType)propSpec.propType) { case PropSpecType.Id: { PropId = propSpec.union.propId; break; } case PropSpecType.Name: { PropName = Marshal.PtrToStringUni(propSpec.union.name); break; } default: throw new ArgumentException(SR.Get(SRID.FilterPropSpecUnknownUnionSelector), "propSpec"); } }