// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace SharpGen.Runtime.Win32
{
///
/// Implementation of OLE IPropertyBag2.
///
/// IPropertyBag2
public class PropertyBag : ComObject
{
private IPropertyBag2 nativePropertyBag;
///
/// Initializes a new instance of the class.
///
/// The property bag pointer.
public PropertyBag(IntPtr propertyBagPointer) : base(propertyBagPointer)
{
}
protected override void NativePointerUpdated(IntPtr oldNativePointer)
{
base.NativePointerUpdated(oldNativePointer);
if (NativePointer != IntPtr.Zero)
nativePropertyBag = (IPropertyBag2)Marshal.GetObjectForIUnknown(NativePointer);
else
nativePropertyBag = null;
}
private void CheckIfInitialized()
{
if (nativePropertyBag == null)
throw new InvalidOperationException("This instance is not bound to an unmanaged IPropertyBag2");
}
///
/// Gets the number of properties.
///
public int Count
{
get
{
CheckIfInitialized();
int propertyCount;
nativePropertyBag.CountProperties(out propertyCount);
return propertyCount;
}
}
///
/// Gets the keys.
///
public string[] Keys
{
get
{
CheckIfInitialized();
var keys = new List();
for (int i = 0; i < Count; i++)
{
PROPBAG2 propbag2;
int temp;
nativePropertyBag.GetPropertyInfo(i, 1, out propbag2, out temp);
keys.Add(propbag2.Name);
}
return keys.ToArray();
}
}
///
/// Gets the value of the property with this name.
///
/// The name.
/// Value of the property
public object Get(string name)
{
CheckIfInitialized();
object value;
var propbag2 = new PROPBAG2() {Name = name};
Result error;
// Gets the property
var result = nativePropertyBag.Read(1, ref propbag2, IntPtr.Zero, out value, out error);
if (result.Failure || error.Failure)
throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Property with name [{0}] is not valid for this instance", name));
propbag2.Dispose();
return value;
}
///
/// Gets the value of the property by using a
///
/// The public type of this property.
/// The marshaling type of this property.
/// The property key.
/// Value of the property
public T1 Get(PropertyBagKey propertyKey)
{
var value = Get(propertyKey.Name);
return (T1) Convert.ChangeType(value, typeof (T1));
}
///
/// Sets the value of the property with this name
///
/// The name.
/// The value.
public void Set(string name, object value)
{
CheckIfInitialized();
// In order to set a property in the property bag
// we need to convert the value to the destination type
var previousValue = Get(name);
value = Convert.ChangeType(value, previousValue==null?value.GetType() : previousValue.GetType());
// Set the property
var propbag2 = new PROPBAG2() { Name = name };
var result = nativePropertyBag.Write(1, ref propbag2, value);
result.CheckError();
propbag2.Dispose();
}
///
/// Sets the value of the property by using a
///
/// The public type of this property.
/// The marshaling type of this property.
/// The property key.
/// The value.
public void Set(PropertyBagKey propertyKey, T1 value)
{
Set(propertyKey.Name, value);
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct PROPBAG2 : IDisposable
{
internal uint type;
internal ushort vt;
internal ushort cfType;
internal IntPtr dwHint;
internal IntPtr pstrName;
internal Guid clsid;
public string Name
{
get
{
unsafe
{
return Marshal.PtrToStringUni(pstrName);
}
}
set
{
pstrName = Marshal.StringToCoTaskMemUni(value);
}
}
public void Dispose()
{
if (pstrName != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pstrName);
pstrName = IntPtr.Zero;
}
}
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("22F55882-280B-11D0-A8A9-00A0C90C2004")]
private interface IPropertyBag2
{
[PreserveSig()]
Result Read([In] int cProperties, [In] ref PROPBAG2 pPropBag, IntPtr pErrLog, [Out] out object pvarValue, out Result phrError);
[PreserveSig()]
Result Write([In] int cProperties, [In] ref PROPBAG2 pPropBag, ref object value);
[PreserveSig()]
Result CountProperties(out int pcProperties);
[PreserveSig()]
Result GetPropertyInfo([In] int iProperty, [In] int cProperties, out PROPBAG2 pPropBag, out int pcProperties);
[PreserveSig()]
Result LoadObject([In, MarshalAs(UnmanagedType.LPWStr)] string pstrName, [In] uint dwHint, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkObject, IntPtr pErrLog);
}
}
}