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
// https://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));
}
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:
#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
...
Comments
- Anonymous
February 25, 2007
PingBack from http://cheatcodedirect.com/itempropertyset-accessing-the-property-system-from-managed-code/