ItemPropertySet: accessing the Property System from managed code…


So, this code should eventually make it to the VistaBridge Windows SDK code sample (“no official support”). It’s in C++/CLI as it uses macros and templates quite a lot…


It is really a beta version as I’d love to have other people use it and tell me what’s wrong or missing.


I’m including here the code without most property macro (they are 800+ !) but you can download the zip file and examine it.


As you can see below, you can access the properties by name or by PropertyKey (in case its’a custom one):



PropertyKey pk = new PropertyKey(new Guid(“F29F85E0-4FF9-1068-AB91-08002B27B3D9”), 6);


using (ItemPropertySet ips = new ItemPropertySet(textboxPath.Text, GetPropertyStoreFlag.ReadWrite)) {


    object o = ips.GetValue(pk);


    string comment = o as string;


    System.Diagnostics.Debug.Assert(comment == ips.Comment);


    ips.Comment = “A first comment to test the writing of property”;


    System.Diagnostics.Debug.Assert(ips.Comment == (string) ips.GetValue(pk));


}


using (ItemPropertySet ips = new ItemPropertySet(textboxPath.Text, GetPropertyStoreFlag.ReadWrite)) {


    ips.SetValue(pk, “A second comment to test the writing of property”);


}


 


The C++/CLI code:



#include “stdafx.h”


using namespace System::Runtime::InteropServices;


using namespace System;


 


// ********************************************************************************


// *


// * The VariantType template class helps mapping the VARTYPE (e.g. VT_LPWSTR) to a


// * CLR type (e.g. String ^).


// *


// ********************************************************************************


 


template <typename T>


class VariantType {


public:


   const static VARTYPE vartype;


};


 


template <typename T>


const VARTYPE VariantType<T>::vartype = VT_ILLEGAL;


const VARTYPE VariantType<Int16>::vartype = VT_I2;


const VARTYPE VariantType<Int32>::vartype = VT_I4;


const VARTYPE VariantType<Byte>::vartype = VT_UI1;


const VARTYPE VariantType<UInt16>::vartype = VT_UI2;


const VARTYPE VariantType<UInt32>::vartype = VT_UI4;


const VARTYPE VariantType<UInt64>::vartype = VT_UI8;


const VARTYPE VariantType<Double>::vartype = VT_R8;


const VARTYPE VariantType<bool>::vartype = VT_BOOL;


const VARTYPE VariantType<ComTypes::FILETIME>::vartype = VT_FILETIME;


const VARTYPE VariantType<Guid>::vartype = VT_CLSID;


const VARTYPE VariantType<String ^>::vartype = VT_LPWSTR;


 


 


// ********************************************************************************


// *


// * Overloaded GetValueFromPropertyVariant functions to help with the mapping from PROPVARIANT.


// *


// ********************************************************************************


 


static HRESULT GetValue(const PROPVARIANT & propertyVariant, Byte % value) {


   if (propertyVariant.vt == VT_UI1) {


      value = propertyVariant.bVal;


      return S_OK;


   }


   return E_INVALIDARG;


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, Int16 % value) {


   SHORT i16;


   HRESULT hr = PropVariantGetInt16Elem(propertyVariant, 0, & i16);


   if SUCCEEDED(hr)


      value = i16;


   return hr;


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, Int32 % value) {


   LONG i32;


   HRESULT hr = PropVariantGetInt32Elem(propertyVariant, 0, & i32);


   if SUCCEEDED(hr)


      value = i32;


   return hr;  


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, UInt16 % value) {


   USHORT ui16;


   HRESULT hr = PropVariantGetUInt16Elem(propertyVariant, 0, & ui16);


   if SUCCEEDED(hr)


      value = ui16;


   return hr;  


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, UInt32 % value) {


   ULONG ui32;


   HRESULT hr = PropVariantGetUInt32Elem(propertyVariant, 0, & ui32);


   if SUCCEEDED(hr)


      value = ui32;


   return hr;  


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, UInt64 % value) {


   ULONGLONG ui64;


   HRESULT hr = PropVariantGetUInt64Elem(propertyVariant, 0, & ui64);


   if SUCCEEDED(hr)


      value = ui64;


   return hr;  


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, Double % value) {


   Double d;


   HRESULT hr = PropVariantGetDoubleElem(propertyVariant, 0, & d);


   if SUCCEEDED(hr)


      value = d;


   return hr;  


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, bool % value) {


   BOOL b;


   HRESULT hr = PropVariantGetBooleanElem(propertyVariant, 0, & b);


   if SUCCEEDED(hr)


      value = (b != FALSE);


   return hr;


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, ComTypes::FILETIME % value) {


   ::FILETIME filetime;


   HRESULT hr = PropVariantGetFileTimeElem(propertyVariant, 0, & filetime);


   if SUCCEEDED(hr) {


      value.dwHighDateTime = filetime.dwHighDateTime;


      value.dwLowDateTime = filetime.dwLowDateTime;


   }


   return hr;


}


static HRESULT GetValue(const PROPVARIANT & propertyVariant, System::Guid % value) {


   CLSID clsid;


   HRESULT hr = PropVariantToCLSID(propertyVariant, & clsid);


   if SUCCEEDED(hr) {


      value = Guid( clsid.Data1, clsid.Data2, clsid.Data3, clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]);


   }


   return hr;


}


 


static HRESULT GetValue(const PROPVARIANT & propertyVariant, String ^ % value) {


   BSTR bstr;


   HRESULT hr = PropVariantToBSTR(propertyVariant,& bstr);


   if SUCCEEDED(hr) {


      try {


         value = System::Runtime::InteropServices::Marshal::PtrToStringBSTR( (IntPtr) bstr);


      } finally {


         SysFreeString(bstr);


      }


   }


   return hr;


}


 


// ********************************************************************************


// *


// * GetValueFromPropertyVariant template functions


// *


// ********************************************************************************


 


template <typename T>


static void GetValueFromPropertyVariant(const PROPVARIANT & propertyVariant, T % element) {


   if (propertyVariant.vt != VariantType<T>::vartype)


      throw gcnew Exception(String::Format(“Wrong property VARTYPE (expected {0}, actual {1})”, VariantType<T>::vartype, propertyVariant.vt));


   Tif(GetValue(propertyVariant, element));


}


 


template <typename T>


static void GetValueFromPropertyVariant(const PROPVARIANT & propertyVariant, array<T> ^ % elements) {


   ULONG count = PropVariantGetElementCount(propertyVariant);


   if (count) {


      elements = gcnew array<T>(count);


      for(ULONG i = 0; i < count; i++) {


         PROPVARIANT propertyVariantElement;


         try {


            Tif(PropVariantGetElem(propertyVariant, i, & propertyVariantElement));


            Tif(GetValue(propertyVariantElement, elements[i]));


         } finally {


            PropVariantClear(& propertyVariantElement);


         }


      }


   } else {


      elements = nullptr;


   }


}


 


// ********************************************************************************


// *


// * SetPropertyVariant functions


// *


// ********************************************************************************


 


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, Double % value) {


   return InitPropVariantFromDouble(value,propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const Double * valueArray, ULONG elementCount) {


   return InitPropVariantFromDoubleVector(valueArray, elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, Byte % value) {


   propertyVariant->vt = VT_UI1;


   propertyVariant->bVal = value;


   return S_OK;


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, bool % value) {


   return InitPropVariantFromBoolean(value,propertyVariant); // the bool will be converted to a BOOL when pushing the value on the stack


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const bool * valueArray, ULONG elementCount) {


   // Double marshalling from Boolean on the managed heap before entering here, then from


   // bool on the native heap to BOOL on the native heap!


   BOOL * p = new BOOL[elementCount];


   BOOL * to = p;


   const bool * from = valueArray;


   try {


      for(ULONG l = 0; l < elementCount; l++) {


         *to++ = *from++;


      }


      return InitPropVariantFromBooleanVector(p, elementCount, propertyVariant);


   } finally {


      delete [] p;


   }


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, Int16 % value) {


   return InitPropVariantFromInt16(value, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const Int16 * valueArray, ULONG elementCount) {


   return InitPropVariantFromInt16Vector(valueArray, elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, Int32 % value) {


   return InitPropVariantFromInt32(value, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const Int32 * valueArray, ULONG elementCount) {


   return InitPropVariantFromInt32Vector(reinterpret_cast<LONG *>(const_cast<Int32 *>(valueArray)), elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, UInt16 % value) {


   return InitPropVariantFromUInt16(value, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const UInt16 * valueArray, ULONG elementCount) {


   return InitPropVariantFromUInt16Vector(valueArray, elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, UInt32 % value) {


   return InitPropVariantFromUInt32(value, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const UInt32 * valueArray, ULONG elementCount) {


   return InitPropVariantFromUInt32Vector(reinterpret_cast<ULONG *>(const_cast<UInt32 *>(valueArray)), elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, UInt64 % value) {


   return InitPropVariantFromUInt64(value, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const UInt64 * valueArray, ULONG elementCount) {


   return InitPropVariantFromUInt64Vector(valueArray, elementCount, propertyVariant);


}


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, ComTypes::FILETIME % value) {


   pin_ptr<ComTypes::FILETIME> filetime = & value;


   return InitPropVariantFromFileTime(reinterpret_cast<::FILETIME *>(filetime),propertyVariant);


}


 


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, const ::FILETIME * valueArray, ULONG elementCount) {


   return InitPropVariantFromFileTimeVector(valueArray, elementCount, propertyVariant);


}


 


static HRESULT SetPropertyVariant(PROPVARIANT * propertyVariant, Guid % value) {


   // How to: Convert Between System::Guid and _GUID


   // http://msdn2.microsoft.com/en-us/library/wb8scw8f(VS.80).aspx


   pin_ptr<Byte> p = & value.ToByteArray()[0]; // pin_ptr<Guid> p = & value;


   CLSID & clsid = *reinterpret_cast<CLSID *>(p);


   p = nullptr;


   return InitPropVariantFromCLSID(clsid, propertyVariant);


}


 


// ********************************************************************************


// *


// * SetPropertyVariantFromValue [template] functions


// *


// ********************************************************************************


 


static void SetPropertyVariantFromValue(PROPVARIANT * propertyVariant, String ^ % value) {


   pin_ptr<const wchar_t> p = PtrToStringChars(value);


   Tif(InitPropVariantFromString(p,propertyVariant));


   p = nullptr;


   if (propertyVariant->vt != VT_EMPTY && !(propertyVariant->vt & VariantType<String ^>::vartype))


      throw gcnew Exception(String::Format(“Wrong property VARTYPE (expected {0}, actual {1})”, VariantType<String ^>::vartype, propertyVariant->vt));


}


 


template <typename T>


static void SetPropertyVariantFromValue(PROPVARIANT * propertyVariant, Nullable<T> % value) {


   Tif(SetPropertyVariant(propertyVariant, value.Value));


   if (propertyVariant->vt != VariantType<T>::vartype)


      throw gcnew Exception(String::Format(“Wrong property VARTYPE (expected {0}, actual {1})”, VariantType<T>::vartype, propertyVariant->vt));


}


 


static void SetPropertyVariantFromValue(PROPVARIANT * propertyVariant, array<String ^> ^ % arrayValue) {


   Text::StringBuilder sb;


   for each( String ^ s in arrayValue) {


      sb.Append(s);


      sb.Append(‘;’);


   }


   String ^ s = sb.ToString();


   pin_ptr<const wchar_t> p = PtrToStringChars(s);


   Tif(InitPropVariantFromStringAsVector(p,propertyVariant));


}


 


static void SetPropertyVariantFromValue(PROPVARIANT * /*propertyVariant*/, array<Byte> ^ % /*arrayValue*/) {


   throw gcnew InvalidOperationException(); // TODO: implement


}


 


static void SetPropertyVariantFromValue(PROPVARIANT * propertyVariant, array<ComTypes::FILETIME> ^ % arrayValue) {


   ::FILETIME * p = new ::FILETIME[arrayValue->Length];


   try {


      unsigned int u = 0;


      for each(ComTypes::FILETIME value in arrayValue) {


         // Doing that way, we don’t have to pin the whole array


         p[u].dwHighDateTime = value.dwHighDateTime;


         p[u++].dwLowDateTime = value.dwLowDateTime;


      }


      Tif(SetPropertyVariant(propertyVariant, p, arrayValue->Length));


   } finally {


      delete [] p;


   }


}


 


template <typename T>


static void SetPropertyVariantFromValue(PROPVARIANT * propertyVariant, array<T> ^ % arrayValue) {


   T * p = new T[arrayValue->Length];


   try {


      unsigned int u = 0;


      for each(T value in arrayValue) {


         p[u++] = value;


      }


      Tif(SetPropertyVariant(propertyVariant, p, arrayValue->Length));


   } finally {


      delete [] p;


   }


}


 


// ********************************************************************************


// * PropertyTypeHolder template is a trick to help with the writing of 


// * one and only one ItemPropertySet::[Get|Set]Value() template.


// * It works with value type and reference type (including array).


// ********************************************************************************


 


template <typename PVT, bool IS_REFERENCE_TYPE = __is_ref_array(PVT) || cliext::is_handle<PVT>::value>


ref class PropertyTypeHolder;


 


template <typename PVT>


ref class PropertyTypeHolder<PVT, true> {


public:


   typedef PVT type;


   static PVT null = nullptr;


   static bool IsNull(type o) {return o == null;}


};


 


template <typename PVT>


ref class PropertyTypeHolder<PVT, false> {


public:


   typedef Nullable<PVT> type;


   static Nullable<PVT> null;


   static bool IsNull(type % o) {return ! o.HasValue;}


};


 


namespace Microsoft { namespace SDK { namespace Samples { namespace VistaBridge { namespace Library { namespace Shell {


 


// ********************************************************************************


// *


// * PropertyKey managed value class


// *


// ********************************************************************************


 


public value class PropertyKey {


internal:


   PROPERTYKEY Native() {


      pin_ptr<Byte> p = & PropertyGuid.ToByteArray()[0];


      PROPERTYKEY propertyKey = {*reinterpret_cast<CLSID *>(p), PropertyIdentifier};


      return propertyKey;


   }


public:


   PropertyKey(Guid propertyGuid) : PropertyGuid(propertyGuid), PropertyIdentifier(PID_FIRST_USABLE) {


   }


   PropertyKey(Guid propertyGuid, UInt32 propertyIdentifier) : PropertyGuid(propertyGuid), PropertyIdentifier(propertyIdentifier) {


   }


   Guid   PropertyGuid;


   UInt32 PropertyIdentifier;


};


 


// ********************************************************************************


// *


// * ItemPropertySet managed reference class


// *


// ********************************************************************************


 


public ref class ItemPropertySet {


private:


   IPropertyStore * _propertyStore;


   bool             _needCommit;


 


protected:


   void Init(String ^ path, GetPropertyStoreFlag flag) {


      IShellItem2Ptr shellItem;


      HRESULT hr;


      pin_ptr<const wchar_t> f = PtrToStringChars(path);


      hr = SHCreateItemFromParsingName(f, NULL, IID_PPV_ARGS(& shellItem));


      f = nullptr;


      if FAILED(hr)


         throw gcnew Exception( String::Format(“Error creating the Shell Item for \”{0}\”.”, path));


      void * v;


      Tif(shellItem->GetPropertyStore(reinterpret_cast<GETPROPERTYSTOREFLAGS &>(flag), IID_IPropertyStore, & v));


      _propertyStore = static_cast<IPropertyStore *>(v);


   }


 


   template <typename T>


   void SetValue(const PROPERTYKEY & propertyKey, typename PropertyTypeHolder<T>::type % value) {


      if(IsNotWritable(propertyKey))


         throw gcnew InvalidOperationException(“This property is not writable”);


      PROPVARIANT propertyVariant;


      try {


         if (PropertyTypeHolder<T>::IsNull(value))


            propertyVariant.vt = VT_EMPTY;


         else {


            SetPropertyVariantFromValue(& propertyVariant, value);


         }


         Tif(_propertyStore->SetValue(propertyKey, propertyVariant));


         _needCommit = true;


      } finally {


         PropVariantClear(& propertyVariant);


      }


   }


 


   template <typename T>


   typename PropertyTypeHolder<T>::type GetValue(const PROPERTYKEY & propertyKey) {


      PROPVARIANT propertyVariant;


      Tif(_propertyStore->GetValue(propertyKey, & propertyVariant));


      try {


         if (propertyVariant.vt == VT_EMPTY)


            return PropertyTypeHolder<T>::null;


         typename T propertyValue;


         GetValueFromPropertyVariant(propertyVariant, propertyValue);


         return propertyValue;


      } finally {


         PropVariantClear(& propertyVariant);


      }


   }


 


   bool IsNotWritable(const PROPERTYKEY & propertyKey) {


      IPropertyStoreCapabilitiesPtr propertyStoreCapabilities;


      return    SUCCEEDED(_propertyStore->QueryInterface(IID_PPV_ARGS(& propertyStoreCapabilities)))


             && S_FALSE == propertyStoreCapabilities->IsPropertyWritable(propertyKey);


   }


 


public:


   ItemPropertySet(String ^ path, GetPropertyStoreFlag flag) {


      Init(path, flag);


   }


 


   ItemPropertySet(String ^ path) {


      Init(path, GetPropertyStoreFlag::Default);


   }


 


 


   ~ItemPropertySet() {


      ItemPropertySet::!ItemPropertySet();


   }


 


   !ItemPropertySet() {


      if (_needCommit) {


         System::Diagnostics::Debug::WriteLine(“ItemPropertySet instance did not call Commit() although it might have needed to.”);


         _needCommit = false;


      }


 


      if (_propertyStore)


         _propertyStore->Release();


   }


 


   bool IsNotWritable(PropertyKey propertyKey) {


      return IsNotWritable(propertyKey.Native());


   }


 


   Object ^ GetValue(PropertyKey managedPropertyKey) {


      PROPVARIANT propertyVariant;


      Tif(_propertyStore->GetValue(managedPropertyKey.Native(), & propertyVariant));


      if (propertyVariant.vt == VT_EMPTY)


         return nullptr;


 


      try {


         if (propertyVariant.vt & VT_VECTOR) {


            #pragma push_macro(“HANDLE_CASE”)


            #define HANDLE_CASE(T) case VariantType<T>::vartype: {array<T> ^ t; ::GetValueFromPropertyVariant(propertyVariant, t); return t;}


            switch (propertyVariant.vt & ~VT_VECTOR) {


               HANDLE_CASE(Byte)


               HANDLE_CASE(UInt16)


               HANDLE_CASE(UInt32)


               HANDLE_CASE(UInt64)


               HANDLE_CASE(Int16)


               HANDLE_CASE(Int32)


               HANDLE_CASE(Double)


               HANDLE_CASE(bool)


               HANDLE_CASE(ComTypes::FILETIME)


               HANDLE_CASE(Guid)


               HANDLE_CASE(String ^)


            }


            #undef HANDLE_CASE


         } else {


            #define HANDLE_CASE(T) case VariantType<T>::vartype: {T t; Tif(::GetValue(propertyVariant, t)); return t;}


            switch (propertyVariant.vt) {


               HANDLE_CASE(Byte)


               HANDLE_CASE(UInt16)


               HANDLE_CASE(UInt32)


               HANDLE_CASE(UInt64)


               HANDLE_CASE(Int16)


               HANDLE_CASE(Int32)


               HANDLE_CASE(Double)


               HANDLE_CASE(bool)


               HANDLE_CASE(ComTypes::FILETIME)


               HANDLE_CASE(Guid)


               HANDLE_CASE(String ^)


            }


            #undef HANDLE_CASE


            #pragma pop_macro(“HANDLE_CASE”)


         }


      } finally {


         PropVariantClear(& propertyVariant);


      }


 


      throw gcnew InvalidOperationException(String::Format(“Unsupported type ({0})”, propertyVariant.vt));


   }


 


   Object ^ GetValue(Guid propertyGuid, UInt32 propertyIdentifier) {


      return GetValue(PropertyKey(propertyGuid,propertyIdentifier));


   }


 


   // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/commit.asp


   void Commit() {


      if (_needCommit) {


         Tif(_propertyStore->Commit());


         _needCommit = false;


      } else {


         System::Diagnostics::Debug::WriteLine(“ItemPropertySet.Commit() was called although it was not need”);


      }


   }


 


   void SetValue(PropertyKey pk, String ^ value)                     {SetValue<String ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Boolean> value)            {SetValue<Boolean>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Byte> value)               {SetValue<Byte>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Int16> value)              {SetValue<Int16>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Int32> value)              {SetValue<Int32>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<UInt16> value)             {SetValue<UInt16>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<UInt32> value)             {SetValue<UInt32>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<UInt64> value)             {SetValue<UInt64>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Double> value)             {SetValue<Double>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<ComTypes::FILETIME> value) {SetValue<ComTypes::FILETIME>(pk.Native(), value);}


   void SetValue(PropertyKey pk, Nullable<Guid> value)               {SetValue<Guid>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<String ^> ^ value)            {SetValue<array<String ^> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<Boolean> ^value)              {SetValue<array<Boolean> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<Byte> ^ value)                {SetValue<array<Byte> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<Int16> ^ value)               {SetValue<array<Int16> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<Int32> ^ value)               {SetValue<array<Int32> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<UInt16> ^ value)              {SetValue<array<UInt16> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<UInt32> ^ value)              {SetValue<array<UInt32> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<UInt64> ^ value)              {SetValue<array<UInt64> ^> (pk.Native(), value);}


   void SetValue(PropertyKey pk, array<Double> ^ value)              {SetValue<array<Double> ^>(pk.Native(), value);}


   void SetValue(PropertyKey pk, array<ComTypes::FILETIME> ^ value)  {SetValue<array<ComTypes::FILETIME> ^>(pk.Native(), value);}


   //void SetValue(PropertyKey pk, array<Guid> ^ value)               {SetValue<array<Guid> ^>(pk.Native(), value);}


 


   // And now for the properties:


   // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_size.asp


   #define PROPERTY_GETTER(PK, T) PropertyTypeHolder<T>::type get() {return GetValue<T>(PK);}


   #define PROPERTY_SETTER(PK, T) void set(PropertyTypeHolder<T>::type value) {SetValue<T>(PK, value);}


   #define PROPERTY(PK, T, N)    property PropertyTypeHolder<T>::type N {PROPERTY_GETTER(PK, T) PROPERTY_SETTER(PK, T)}


   #define PROPERTY_R(PK, T, N) property PropertyTypeHolder<T>::type N {PROPERTY_GETTER(PK, T)}


   // #define PROPERTY_W(PK, T, N) property PropertyTypeHolder<T>::type N {PROPERTY_SETTER(PK, T)}


 


   // I use the full namespace so that I can have a property of the same type as its name (e.g. NoteColor of type NoteColor)


   #define PROPERTY_WRAPPER_GETTER(FROM_TYPE, TO_TYPE, NAME)\


      Nullable<::Microsoft::SDK::Samples::VistaBridge::Library::Shell::TO_TYPE> get() {\


         Nullable<FROM_TYPE> u = NAME;\


         return u.HasValue ? static_cast<::Microsoft::SDK::Samples::VistaBridge::Library::Shell::TO_TYPE>(u.Value) : Nullable<::Microsoft::SDK::Samples::VistaBridge::Library::Shell::TO_TYPE>();\


      }


   #define PROPERTY_WRAPPER_SETTER(FROM_TYPE, TO_TYPE, NAME)\


      void set(Nullable<::Microsoft::SDK::Samples::VistaBridge::Library::Shell::TO_TYPE> value) {\


         NAME = value.HasValue ? static_cast<FROM_TYPE>(value.Value) : Nullable<FROM_TYPE>();\


      }


   #define PROPERTY_WRAPPER_R(FROM_TYPE, TO_TYPE, NAME) property Nullable<TO_TYPE> NAME {PROPERTY_WRAPPER_GETTER(FROM_TYPE, TO_TYPE, NAME##Raw)}


   //#define PROPERTY_WRAPPER_W(FROM_TYPE, TO_TYPE, NAME) property Nullable<TO_TYPE> NAME {PROPERTY_WRAPPER_SETTER(FROM_TYPE, TO_TYPE, NAME##Raw)}


   #define PROPERTY_WRAPPER(FROM_TYPE, TO_TYPE, NAME) property Nullable<TO_TYPE> NAME {PROPERTY_WRAPPER_GETTER(FROM_TYPE, TO_TYPE, NAME##Raw) PROPERTY_WRAPPER_SETTER(FROM_TYPE, TO_TYPE, NAME##Raw)}


 


#pragma region Audio properties


   PROPERTY_R(PKEY_Audio_ChannelCount, UInt32, AudioChannelCountRaw)


   PROPERTY_WRAPPER_R(UInt32, ChannelCount, AudioChannelCount)


   PROPERTY_R(PKEY_Audio_Compression, String ^, AudioCompression)


   PROPERTY_R(PKEY_Audio_EncodingBitrate, UInt32, AudioEncodingBitrate)


   PROPERTY_R(PKEY_Audio_Format, String ^, AudioFormat)


   PROPERTY_R(PKEY_Audio_IsVariableBitRate, bool, AudioIsVariableBitRate)


   PROPERTY_R(PKEY_Audio_PeakValue, UInt32, AudioPeakValue)


   PROPERTY_R(PKEY_Audio_SampleRate, UInt32, AudioSampleRate)


   PROPERTY_R(PKEY_Audio_SampleSize, UInt32, AudioSampleSize)


   PROPERTY_R(PKEY_Audio_StreamName, String ^, AudioStreamName)


   PROPERTY_R(PKEY_Audio_StreamNumber, UInt16, AudioStreamNumber)


#pragma endregion


#pragma region Calendar properties


ItemPropertySet 10.zip