diff --git a/src/libraries/System.Data.OleDb/src/DbPropSet.cs b/src/libraries/System.Data.OleDb/src/DbPropSet.cs index c0b719c737372d..0adeb559986882 100644 --- a/src/libraries/System.Data.OleDb/src/DbPropSet.cs +++ b/src/libraries/System.Data.OleDb/src/DbPropSet.cs @@ -105,9 +105,17 @@ private void SetLastErrorInfo(OleDbHResult lastErrorHr) 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 + try + { + 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 + } + finally + { + UnsafeNativeMethods.ReleaseErrorInfoObject(errorInfo); + } } + lastErrorFromProvider = new COMException(message, (int)lastErrorHr); } diff --git a/src/libraries/System.Data.OleDb/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Data.OleDb/src/ILLink/ILLink.Suppressions.xml index 52bca59a2fc21b..c9d79f066f046c 100644 --- a/src/libraries/System.Data.OleDb/src/ILLink/ILLink.Suppressions.xml +++ b/src/libraries/System.Data.OleDb/src/ILLink/ILLink.Suppressions.xml @@ -1,30 +1,6 @@  - - ILLink - IL2050 - member - M:System.Data.OleDb.DBPropSet.SetLastErrorInfo(System.Data.OleDb.OleDbHResult) - - - ILLink - IL2050 - member - M:System.Data.OleDb.OleDbConnection.ProcessResults(System.Data.OleDb.OleDbHResult,System.Data.OleDb.OleDbConnection,System.Object) - - - ILLink - IL2050 - member - M:System.Data.OleDb.OleDbDataAdapter.FillClose(System.Boolean,System.Object) - - - ILLink - IL2050 - member - M:System.Data.OleDb.OleDbDataAdapter.FillFromADODB(System.Object,System.Object,System.String,System.Boolean) - ILLink IL2067 @@ -102,5 +78,6 @@ IL2111 member M:System.Data.OleDb.OleDbDataReader.BuildSchemaTable(System.Data.OleDb.MetaData[]) - - \ No newline at end of file + + + diff --git a/src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs b/src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs new file mode 100644 index 00000000000000..92a54fe9e223ed --- /dev/null +++ b/src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Diagnostics; +using System.Data.Common; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Data.OleDb +{ + /// + /// The ComWrappers implementation for System.Data.OleDb's COM interop usages. + /// + /// Supports IErrorInfo COM interface. + /// + internal unsafe sealed class OleDbComWrappers : ComWrappers + { + private const int S_OK = (int)OleDbHResult.S_OK; + private static readonly Guid IID_IErrorInfo = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19); + + internal static OleDbComWrappers Instance { get; } = new OleDbComWrappers(); + + private OleDbComWrappers() { } + + protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) + { + throw new NotImplementedException(); + } + + protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags) + { + Debug.Assert(flags == CreateObjectFlags.UniqueInstance); + + Guid errorInfoIID = IID_IErrorInfo; + int hr = Marshal.QueryInterface(externalComObject, ref errorInfoIID, out IntPtr comObject); + if (hr == S_OK) + { + return new ErrorInfoWrapper(comObject); + } + + throw new NotImplementedException(); + } + + protected override void ReleaseObjects(IEnumerable objects) + { + throw new NotImplementedException(); + } + + // Doc and type layout: https://docs.microsoft.com/windows/win32/api/oaidl/nn-oaidl-ierrorinfo + private class ErrorInfoWrapper : UnsafeNativeMethods.IErrorInfo, IDisposable + { + private readonly IntPtr _wrappedInstance; + + public ErrorInfoWrapper(IntPtr wrappedInstance) + { + _wrappedInstance = wrappedInstance; + } + + public void Dispose() + { + Marshal.Release(_wrappedInstance); + } + + [Obsolete("not used", true)] + void UnsafeNativeMethods.IErrorInfo.GetGUID(/*deleted parameter signature*/) + { + throw new NotImplementedException(); + } + + public unsafe System.Data.OleDb.OleDbHResult GetSource(out string? source) + { + IntPtr pSource = IntPtr.Zero; + int errorCode = ((delegate* unmanaged)(*(*(void***)_wrappedInstance + 4 /* IErrorInfo.GetSource slot */))) + (_wrappedInstance, &pSource); + if (pSource == IntPtr.Zero || errorCode < 0) + { + source = null; + } + else + { + source = Marshal.PtrToStringBSTR(pSource); + } + + if (pSource != IntPtr.Zero) + { + Marshal.FreeBSTR(pSource); + } + + return (System.Data.OleDb.OleDbHResult)errorCode; + } + + public unsafe System.Data.OleDb.OleDbHResult GetDescription(out string? description) + { + IntPtr pDescription = IntPtr.Zero; + int errorCode = ((delegate* unmanaged)(*(*(void***)_wrappedInstance + 5 /* IErrorInfo.GetDescription slot */))) + (_wrappedInstance, &pDescription); + if (pDescription == IntPtr.Zero || errorCode < 0) + { + description = null; + } + else + { + description = Marshal.PtrToStringBSTR(pDescription); + } + + if (pDescription != IntPtr.Zero) + { + Marshal.FreeBSTR(pDescription); + } + + return (System.Data.OleDb.OleDbHResult)errorCode; + } + } + + } +} diff --git a/src/libraries/System.Data.OleDb/src/OleDbConnection.cs b/src/libraries/System.Data.OleDb/src/OleDbConnection.cs index 8d78f2ac49323e..7e456b936fba7b 100644 --- a/src/libraries/System.Data.OleDb/src/OleDbConnection.cs +++ b/src/libraries/System.Data.OleDb/src/OleDbConnection.cs @@ -587,32 +587,35 @@ internal bool SupportSchemaRowset(Guid schema) OleDbHResult hr = UnsafeNativeMethods.GetErrorInfo(0, out errorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo if ((OleDbHResult.S_OK == hr) && (null != errorInfo)) { - if (hresult < 0) + try { - // UNDONE: if authentication failed - throw a unique exception object type - //if (/*OLEDB_Error.DB_SEC_E_AUTH_FAILED*/unchecked((int)0x80040E4D) == hr) { - //} - //else if (/*OLEDB_Error.DB_E_CANCELED*/unchecked((int)0x80040E4E) == hr) { - //} - // else { - e = OleDbException.CreateException(errorInfo, hresult, null); - //} - - if (OleDbHResult.DB_E_OBJECTOPEN == hresult) + if (hresult < 0) { - e = ADP.OpenReaderExists(e); - } + // UNDONE: if authentication failed - throw a unique exception object type + //if (/*OLEDB_Error.DB_SEC_E_AUTH_FAILED*/unchecked((int)0x80040E4D) == hr) { + //} + //else if (/*OLEDB_Error.DB_E_CANCELED*/unchecked((int)0x80040E4E) == hr) { + //} + // else { + e = OleDbException.CreateException(errorInfo, hresult, null); + //} + + if (OleDbHResult.DB_E_OBJECTOPEN == hresult) + { + e = ADP.OpenReaderExists(e); + } - ResetState(connection); - } - else if (null != connection) - { - connection.OnInfoMessage(errorInfo, hresult); + ResetState(connection); + } + else if (null != connection) + { + connection.OnInfoMessage(errorInfo, hresult); + } } - else + finally { + UnsafeNativeMethods.ReleaseErrorInfoObject(errorInfo); } - Marshal.ReleaseComObject(errorInfo); } else if (0 < hresult) { diff --git a/src/libraries/System.Data.OleDb/src/OleDbDataAdapter.cs b/src/libraries/System.Data.OleDb/src/OleDbDataAdapter.cs index 9c6fb06c90101c..7972bb788617ed 100644 --- a/src/libraries/System.Data.OleDb/src/OleDbDataAdapter.cs +++ b/src/libraries/System.Data.OleDb/src/OleDbDataAdapter.cs @@ -259,8 +259,7 @@ record = (adodb as UnsafeNativeMethods.ADORecordConstruction); // Current provider does not support returning multiple recordsets from a single execution. if (ODB.ADODB_NextResultError != (int)hr) { - UnsafeNativeMethods.IErrorInfo? errorInfo = null; - UnsafeNativeMethods.GetErrorInfo(0, out errorInfo); + SafeNativeMethods.Wrapper.ClearErrorInfo(); string message = string.Empty; throw new COMException(message, (int)hr); @@ -430,8 +429,7 @@ private void FillClose(bool isrecordset, object value) } if ((0 < (int)hr) && (ODB.ADODB_AlreadyClosedError != (int)hr)) { - UnsafeNativeMethods.IErrorInfo? errorInfo = null; - UnsafeNativeMethods.GetErrorInfo(0, out errorInfo); + SafeNativeMethods.Wrapper.ClearErrorInfo(); string message = string.Empty; throw new COMException(message, (int)hr); } diff --git a/src/libraries/System.Data.OleDb/src/OleDbException.cs b/src/libraries/System.Data.OleDb/src/OleDbException.cs index be01b4b4f00849..31205aa04acd67 100644 --- a/src/libraries/System.Data.OleDb/src/OleDbException.cs +++ b/src/libraries/System.Data.OleDb/src/OleDbException.cs @@ -70,13 +70,8 @@ internal static OleDbException CreateException(UnsafeNativeMethods.IErrorInfo er string? message = null; string? source = null; OleDbHResult hr = 0; - - if (null != errorInfo) - { - hr = errorInfo.GetDescription(out message); - - hr = errorInfo.GetSource(out source); - } + hr = errorInfo.GetDescription(out message); + hr = errorInfo.GetSource(out source); int count = errors.Count; if (0 < errors.Count) diff --git a/src/libraries/System.Data.OleDb/src/OleDb_Util.cs b/src/libraries/System.Data.OleDb/src/OleDb_Util.cs index 1426320311c419..2598fb5dfd553c 100644 --- a/src/libraries/System.Data.OleDb/src/OleDb_Util.cs +++ b/src/libraries/System.Data.OleDb/src/OleDb_Util.cs @@ -334,7 +334,7 @@ internal static InvalidOperationException DBBindingGetVector() internal static OleDbHResult GetErrorDescription(UnsafeNativeMethods.IErrorInfo errorInfo, OleDbHResult hresult, out string message) { - OleDbHResult hr = errorInfo.GetDescription(out message); + OleDbHResult hr = errorInfo.GetDescription(out message!); if (((int)hr < 0) && ADP.IsEmpty(message)) { message = FailedGetDescription(hr) + Environment.NewLine + ODB.ELookup(hresult); diff --git a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj index a5e9b248302241..e7b80a71a61c34 100644 --- a/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj +++ b/src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj @@ -111,6 +111,13 @@ System.Data.OleDb.OleDbTransaction + + + + + + +