/// <summary>
        /// MarshalPropVariant
        /// </summary>
        /// <param name="obj">Object to marshal, should be DateTime or String</param>
        /// <returns>newly allocated PROPVARIANT structure</returns>
        internal static IntPtr MarshalPropVariant(Object obj)
        {
            IntPtr pszVal  = IntPtr.Zero;
            IntPtr pNative = IntPtr.Zero;

            try
            {
                PROPVARIANT v;

                if (obj is string)
                {
                    pszVal = Marshal.StringToCoTaskMemAnsi((string)obj);

                    v              = new PROPVARIANT();
                    v.vt           = VARTYPE.VT_LPSTR;
                    v.union.pszVal = pszVal;
                }
                else if (obj is DateTime)
                {
                    v    = new PROPVARIANT();
                    v.vt = VARTYPE.VT_FILETIME;
                    long longFileTime = ((DateTime)obj).ToFileTime();
                    v.union.filetime.dwLowDateTime  = (Int32)longFileTime;
                    v.union.filetime.dwHighDateTime = (Int32)((longFileTime >> 32) & 0xFFFFFFFF);
                }
                else
                {
                    throw new InvalidOperationException(
                              SR.Get(SRID.FilterGetValueMustBeStringOrDateTime));
                }

                // allocate an unmanaged PROPVARIANT to return
                pNative = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(PROPVARIANT)));

                // Per MSDN, AllocCoTaskMem never returns null: check for IntPtr.Zero instead.
                Invariant.Assert(pNative != IntPtr.Zero);

                // marshal the managed PROPVARIANT into the unmanaged block and return it
                Marshal.StructureToPtr(v, pNative, false);
            }
            catch
            {
                if (pszVal != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pszVal);
                }

                if (pNative != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(pNative);
                }

                throw;
            }

            return(pNative);
        }
Example #2
0
        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);
                }
            }
        }
Example #3
0
        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);
        }