File: System\Data\OleDb\PropertyInfoSet.cs
Project: ndp\fx\src\data\System.Data.csproj (System.Data)
//------------------------------------------------------------------------------
// <copyright file="PropertyInfoSet.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
 
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Runtime.ConstrainedExecution;
 
namespace System.Data.OleDb {
 
    sealed internal class OleDbPropertyInfo {
        public Guid _propertySet;
        public Int32 _propertyID;
        public string _description;
        public string _lowercase;
        public Type   _type;
 
        public int _flags;
        public int _vtype;
        public object _supportedValues;
 
        public object _defaultValue;
    }
 
    internal sealed class PropertyInfoSet : SafeHandle {
 
        private int setCount;
        private IntPtr descBuffer;
 
        internal PropertyInfoSet(UnsafeNativeMethods.IDBProperties idbProperties, PropertyIDSet propIDSet) : base(IntPtr.Zero, true) {
            OleDbHResult hr;
            int propIDSetCount = propIDSet.Count; // avoid need for ReliabilityContract on get_Count
            Bid.Trace("<oledb.IDBProperties.GetPropertyInfo|API|OLEDB>\n");
            RuntimeHelpers.PrepareConstrainedRegions();
            try {} finally {
                hr = idbProperties.GetPropertyInfo(propIDSetCount, propIDSet, out this.setCount, out base.handle, out this.descBuffer);
            }
            Bid.Trace("<oledb.IDBProperties.GetPropertyInfo|API|OLEDB|RET> %08X{HRESULT}\n", hr);
            if ((0 <= hr) && (ADP.PtrZero != handle)) {
                SafeNativeMethods.Wrapper.ClearErrorInfo();
            }
        }
 
        public override bool IsInvalid {
            get {
                return ((IntPtr.Zero == base.handle) && (IntPtr.Zero == this.descBuffer));
            }
        }
 
        internal Dictionary<string,OleDbPropertyInfo> GetValues() {
            Dictionary<string,OleDbPropertyInfo> propertyLookup = null;
            
            bool mustRelease = false;            
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                DangerousAddRef(ref mustRelease);
                if (ADP.PtrZero != this.handle) {
                    propertyLookup = new Dictionary<string,OleDbPropertyInfo>(StringComparer.OrdinalIgnoreCase);
 
                    IntPtr setPtr = this.handle;
                    tagDBPROPINFO propinfo = new tagDBPROPINFO();
                    tagDBPROPINFOSET propinfoset = new tagDBPROPINFOSET();
 
                    for (int i = 0; i < setCount; ++i, setPtr = ADP.IntPtrOffset(setPtr, ODB.SizeOf_tagDBPROPINFOSET)) {
                        Marshal.PtrToStructure(setPtr, propinfoset);
 
                        int infoCount = propinfoset.cPropertyInfos;
                        IntPtr infoPtr = propinfoset.rgPropertyInfos;
                        for(int k = 0; k < infoCount; ++k, infoPtr = ADP.IntPtrOffset(infoPtr, ODB.SizeOf_tagDBPROPINFO)) {
                            Marshal.PtrToStructure(infoPtr, propinfo);
 
                            OleDbPropertyInfo propertyInfo = new OleDbPropertyInfo();
                            propertyInfo._propertySet = propinfoset.guidPropertySet;
                            propertyInfo._propertyID = propinfo.dwPropertyID;
                            propertyInfo._flags = propinfo.dwFlags;
                            propertyInfo._vtype = propinfo.vtType;
                            propertyInfo._supportedValues = propinfo.vValue;
                            propertyInfo._description = propinfo.pwszDescription;
                            propertyInfo._lowercase = propinfo.pwszDescription.ToLower(CultureInfo.InvariantCulture);
                            propertyInfo._type = PropertyInfoSet.FromVtType(propinfo.vtType);
 
                            if (Bid.AdvancedOn) {
                                Bid.Trace("<oledb.struct.OleDbPropertyInfo|INFO|ADV> \n");//, propertyInfo);
                            }
                            propertyLookup[propertyInfo._lowercase] = propertyInfo;
                        }
                    }
                }
            }
            finally {
                if (mustRelease) {
                    DangerousRelease();
                }
            }
            return propertyLookup;
        }
 
        override protected bool ReleaseHandle() {
            // NOTE: The SafeHandle class guarantees this will be called exactly once and is non-interrutible.
            IntPtr ptr = base.handle;
            base.handle = IntPtr.Zero;
            if (IntPtr.Zero != ptr) {
                int count = this.setCount;
                for (int i = 0; i < count; ++i) {
                    int offset = (i * ODB.SizeOf_tagDBPROPINFOSET);
                    IntPtr infoPtr = Marshal.ReadIntPtr(ptr, offset);
                    if (IntPtr.Zero != infoPtr) {
                        int infoCount = Marshal.ReadInt32(ptr, offset + ADP.PtrSize);
 
                        for (int k = 0; k < infoCount; ++k) {
                            IntPtr valuePtr = ADP.IntPtrOffset(infoPtr, (k * ODB.SizeOf_tagDBPROPINFO) + ODB.OffsetOf_tagDBPROPINFO_Value);
                            SafeNativeMethods.VariantClear(valuePtr);
                        }
                        SafeNativeMethods.CoTaskMemFree(infoPtr); // was allocated by provider
                    }
                }
                SafeNativeMethods.CoTaskMemFree(ptr);
            }
 
            ptr = this.descBuffer;
            this.descBuffer = IntPtr.Zero;
            if (IntPtr.Zero != ptr) {
                SafeNativeMethods.CoTaskMemFree(ptr);
            }
            return true;
        }
 
        internal static Type FromVtType(int vartype) {
            switch((VarEnum)vartype) {
            case VarEnum.VT_EMPTY:    return null;
            case VarEnum.VT_NULL:     return typeof(System.DBNull);
            case VarEnum.VT_I2:       return typeof(System.Int16);
            case VarEnum.VT_I4:       return typeof(System.Int32);
            case VarEnum.VT_R4:       return typeof(System.Single);
            case VarEnum.VT_R8:       return typeof(System.Double);
            case VarEnum.VT_CY:       return typeof(System.Decimal);
            case VarEnum.VT_DATE:     return typeof(System.DateTime);
            case VarEnum.VT_BSTR:     return typeof(System.String);
            case VarEnum.VT_DISPATCH: return typeof(System.Object);
            case VarEnum.VT_ERROR:    return typeof(System.Int32);
            case VarEnum.VT_BOOL:     return typeof(System.Boolean);
            case VarEnum.VT_VARIANT:  return typeof(System.Object);
            case VarEnum.VT_UNKNOWN:  return typeof(System.Object);
            case VarEnum.VT_DECIMAL:  return typeof(System.Decimal);
            case VarEnum.VT_I1:       return typeof(System.SByte);
            case VarEnum.VT_UI1:      return typeof(System.Byte);
            case VarEnum.VT_UI2:      return typeof(System.UInt16);
            case VarEnum.VT_UI4:      return typeof(System.UInt32);
            case VarEnum.VT_I8:       return typeof(System.Int64);
            case VarEnum.VT_UI8:      return typeof(System.UInt64);
            case VarEnum.VT_INT:      return typeof(System.Int32);
            case VarEnum.VT_UINT:     return typeof(System.UInt32);
            default:          return typeof(System.Object);
            }
        }    }
}