1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
//------------------------------------------------------------------------------
// <copyright file="DBPropSet.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.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 DBPropSet : SafeHandle {
private readonly Int32 propertySetCount;
// VSDD 621427: stores the exception with last error.HRESULT from IDBProperties.GetProperties
private Exception lastErrorFromProvider;
private DBPropSet() : base(IntPtr.Zero, true) {
propertySetCount = 0;
}
internal DBPropSet(int propertysetCount) : this() {
this.propertySetCount = propertysetCount;
IntPtr countOfBytes = (IntPtr)(propertysetCount * ODB.SizeOf_tagDBPROPSET);
RuntimeHelpers.PrepareConstrainedRegions();
try {} finally {
base.handle = SafeNativeMethods.CoTaskMemAlloc(countOfBytes);
if (ADP.PtrZero != base.handle) {
SafeNativeMethods.ZeroMemory(base.handle, countOfBytes);
}
}
if (ADP.PtrZero == base.handle) {
throw new OutOfMemoryException();
}
}
internal DBPropSet(UnsafeNativeMethods.IDBProperties properties, PropertyIDSet propidset, out OleDbHResult hr) : this() {
Debug.Assert(null != properties, "null IDBProperties");
int propidsetcount = 0;
if (null != propidset) {
propidsetcount = propidset.Count;
}
Bid.Trace("<oledb.IDBProperties.GetProperties|API|OLEDB>\n");
hr = properties.GetProperties(propidsetcount, propidset, out this.propertySetCount, out base.handle);
Bid.Trace("<oledb.IDBProperties.GetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
if (hr < 0) {
// VSDD 621427: remember the last HRESULT. Note we do not want to raise exception now to avoid breaking change from Orcas RTM/SP1
SetLastErrorInfo(hr);
}
}
internal DBPropSet(UnsafeNativeMethods.IRowsetInfo properties, PropertyIDSet propidset, out OleDbHResult hr) : this() {
Debug.Assert(null != properties, "null IRowsetInfo");
int propidsetcount = 0;
if (null != propidset) {
propidsetcount = propidset.Count;
}
Bid.Trace("<oledb.IRowsetInfo.GetProperties|API|OLEDB>\n");
hr = properties.GetProperties(propidsetcount, propidset, out this.propertySetCount, out base.handle);
Bid.Trace("<oledb.IRowsetInfo.GetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
if (hr < 0) {
// VSDD 621427: remember the last HRESULT. Note we do not want to raise exception now to avoid breaking change from Orcas RTM/SP1
SetLastErrorInfo(hr);
}
}
internal DBPropSet(UnsafeNativeMethods.ICommandProperties properties, PropertyIDSet propidset, out OleDbHResult hr) : this() {
Debug.Assert(null != properties, "null ICommandProperties");
int propidsetcount = 0;
if (null != propidset) {
propidsetcount = propidset.Count;
}
Bid.Trace("<oledb.ICommandProperties.GetProperties|API|OLEDB>\n");
hr = properties.GetProperties(propidsetcount, propidset, out this.propertySetCount, out base.handle);
Bid.Trace("<oledb.ICommandProperties.GetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
if (hr < 0) {
// VSDD 621427: remember the last HRESULT. Note we do not want to raise exception now to avoid breaking change from Orcas RTM/SP1
SetLastErrorInfo(hr);
}
}
private void SetLastErrorInfo(OleDbHResult lastErrorHr) {
// note: OleDbHResult is actually a simple wrapper over HRESULT with OLEDB-specific codes
UnsafeNativeMethods.IErrorInfo errorInfo = null;
string message = String.Empty;
OleDbHResult errorInfoHr = UnsafeNativeMethods.GetErrorInfo(0, out errorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo
if ((errorInfoHr == OleDbHResult.S_OK) && (errorInfo != null)) {
ODB.GetErrorDescription(errorInfo, lastErrorHr, out message);
// note that either GetErrorInfo or GetErrorDescription might fail in which case we will have only the HRESULT value in exception message
}
lastErrorFromProvider = new COMException(message, (int)lastErrorHr);
}
public override bool IsInvalid {
get {
return (IntPtr.Zero == base.handle);
}
}
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 (ADP.PtrZero != ptr) {
int count = this.propertySetCount;
for (int i = 0, offset = 0; i < count; ++i, offset += ODB.SizeOf_tagDBPROPSET) {
IntPtr rgProperties = Marshal.ReadIntPtr(ptr, offset);
if(ADP.PtrZero != rgProperties) {
int cProperties = Marshal.ReadInt32(ptr, offset + ADP.PtrSize);
IntPtr vptr = ADP.IntPtrOffset(rgProperties, ODB.OffsetOf_tagDBPROP_Value);
for (int k = 0; k < cProperties; ++k, vptr = ADP.IntPtrOffset(vptr, ODB.SizeOf_tagDBPROP)) {
SafeNativeMethods.VariantClear(vptr);
}
SafeNativeMethods.CoTaskMemFree(rgProperties);
}
}
SafeNativeMethods.CoTaskMemFree(ptr);
}
return true;
}
internal int PropertySetCount {
get {
return this.propertySetCount;
}
}
internal tagDBPROP[] GetPropertySet(int index, out Guid propertyset) {
if ((index < 0) || (PropertySetCount <= index)) {
if (lastErrorFromProvider != null)
{
// VSDD 621427: add extra error information for CSS/stress troubleshooting.
// We need to keep same exception type to avoid breaking change with Orcas RTM/SP1.
throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer, lastErrorFromProvider);
}
else {
throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer);
}
}
tagDBPROPSET propset = new tagDBPROPSET();
tagDBPROP[] properties = null;
bool mustRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
DangerousAddRef(ref mustRelease);
IntPtr propertySetPtr = ADP.IntPtrOffset(DangerousGetHandle(), index * ODB.SizeOf_tagDBPROPSET);
Marshal.PtrToStructure(propertySetPtr, propset);
propertyset = propset.guidPropertySet;
properties = new tagDBPROP[propset.cProperties];
for(int i = 0; i < properties.Length; ++i) {
properties[i] = new tagDBPROP();
IntPtr ptr = ADP.IntPtrOffset(propset.rgProperties, i * ODB.SizeOf_tagDBPROP);
Marshal.PtrToStructure(ptr, properties[i]);
}
}
finally {
if (mustRelease) {
DangerousRelease();
}
}
return properties;
}
internal void SetPropertySet(int index, Guid propertySet, tagDBPROP[] properties) {
if ((index < 0) || (PropertySetCount <= index)) {
if (lastErrorFromProvider != null) {
// VSDD 621427: add extra error information for CSS/stress troubleshooting.
// We need to keep same exception type to avoid breaking change with Orcas RTM/SP1.
throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer, lastErrorFromProvider);
}
else {
throw ADP.InternalError(ADP.InternalErrorCode.InvalidBuffer);
}
}
Debug.Assert(Guid.Empty != propertySet, "invalid propertySet");
Debug.Assert((null != properties) && (0 < properties.Length), "invalid properties");
IntPtr countOfBytes = (IntPtr)(properties.Length * ODB.SizeOf_tagDBPROP);
tagDBPROPSET propset = new tagDBPROPSET(properties.Length, propertySet);
bool mustRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
DangerousAddRef(ref mustRelease);
IntPtr propsetPtr = ADP.IntPtrOffset(DangerousGetHandle(), index * ODB.SizeOf_tagDBPROPSET);
RuntimeHelpers.PrepareConstrainedRegions();
try {} finally {
// must allocate and clear the memory without interruption
propset.rgProperties = SafeNativeMethods.CoTaskMemAlloc(countOfBytes);
if (ADP.PtrZero != propset.rgProperties) {
// clearing is important so that we don't treat existing
// garbage as important information during releaseHandle
SafeNativeMethods.ZeroMemory(propset.rgProperties, countOfBytes);
// writing the structure to native memory so that it knows to free the referenced pointers
Marshal.StructureToPtr(propset, propsetPtr, false/*deleteold*/);
}
}
if (ADP.PtrZero == propset.rgProperties) {
throw new OutOfMemoryException();
}
for(int i = 0; i < properties.Length; ++i) {
Debug.Assert(null != properties[i], "null tagDBPROP " + i.ToString(CultureInfo.InvariantCulture));
IntPtr propertyPtr = ADP.IntPtrOffset(propset.rgProperties, i * ODB.SizeOf_tagDBPROP);
Marshal.StructureToPtr(properties[i], propertyPtr, false/*deleteold*/);
}
}
finally {
if (mustRelease) {
DangerousRelease();
}
}
}
static internal DBPropSet CreateProperty(Guid propertySet, int propertyId, bool required, object value) {
tagDBPROP dbprop = new tagDBPROP(propertyId, required, value);
DBPropSet propertyset = new DBPropSet(1);
propertyset.SetPropertySet(0, propertySet, new tagDBPROP[1] { dbprop });
return propertyset;
}
}
}
|