Exemplo n.º 1
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);
                }
            }
        }