Skip to content

Commit

Permalink
First round of converting System.Data.OleDb to COMWrappers
Browse files Browse the repository at this point in the history
This change just remove warning from ILLink and do not make attempt
to convert other COM object creation to use ComWrappers

Also I have to add target net5.0-windows where ComWrappers would be
used. Same concerns regarding testing as in
dotnet#54636

Two calls inside OleDbDataAdapter call GetErrorInfo but do not do anything with results. That's probably mistake from previous refactoring. These parts does not touched and left as is. Need advice on that specific parts how to proceed.
  • Loading branch information
kant2002 committed Jun 28, 2021
1 parent e928680 commit b91ee8d
Show file tree
Hide file tree
Showing 21 changed files with 917 additions and 333 deletions.
31 changes: 31 additions & 0 deletions src/libraries/System.Data.OleDb/src/DbPropSet.COMWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Data.OleDb
{
internal sealed partial class DBPropSet
{
private void SetLastErrorInfo(OleDbHResult lastErrorHr)
{
// note: OleDbHResult is actually a simple wrapper over HRESULT with OLEDB-specific codes
string message = string.Empty;
IntPtr pErrorInfo;
OleDbHResult errorInfoHr = UnsafeNativeMethods.GetErrorInfo(0, out pErrorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo
if ((errorInfoHr == OleDbHResult.S_OK) && (pErrorInfo != IntPtr.Zero))
{
using OleDbComWrappers.IErrorInfo errorInfo = (OleDbComWrappers.IErrorInfo)OleDbComWrappers.Instance
.GetOrCreateObjectForComInstance(pErrorInfo, CreateObjectFlags.UniqueInstance);;
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);
}
}
}
29 changes: 29 additions & 0 deletions src/libraries/System.Data.OleDb/src/DbPropSet.NoCOMWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Data.OleDb
{
internal sealed partial class DBPropSet
{
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);
}
}
}
17 changes: 1 addition & 16 deletions src/libraries/System.Data.OleDb/src/DbPropSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace System.Data.OleDb
{
internal sealed class DBPropSet : SafeHandle
internal sealed partial class DBPropSet : SafeHandle
{
private readonly int propertySetCount;

Expand Down Expand Up @@ -96,21 +96,6 @@ internal DBPropSet(UnsafeNativeMethods.ICommandProperties properties, PropertyID
}
}

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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<linker>
<assembly fullname="System.Data.OleDb, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2050</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.OleDb.DBPropSet.SetLastErrorInfo(System.Data.OleDb.OleDbHResult)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2050</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.OleDb.OleDbConnection.ProcessResults(System.Data.OleDb.OleDbHResult,System.Data.OleDb.OleDbConnection,System.Object)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2050</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.OleDb.OleDbDataAdapter.FillClose(System.Boolean,System.Object)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2050</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.OleDb.OleDbDataAdapter.FillFromADODB(System.Object,System.Object,System.String,System.Boolean)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2067</argument>
Expand Down Expand Up @@ -92,4 +68,4 @@
<property name="Target">M:System.Data.OleDb.OleDbMetaDataFactory.GetDataSourceInformationTable(System.Data.OleDb.OleDbConnection,System.Data.OleDb.OleDbConnectionInternal)</property>
</attribute>
</assembly>
</linker>
</linker>
108 changes: 108 additions & 0 deletions src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// 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.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Data.OleDb
{
/// <summary>
/// The ComWrappers implementation for System.Data.OleDb's COM interop usages.
///
/// Supports IErrorInfo COM interface.
/// </summary>
internal unsafe class OleDbComWrappers : ComWrappers
{
private const int S_OK = (int)Interop.HRESULT.S_OK;

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 = IErrorInfo.IID;
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();
}

internal interface IErrorInfo
{
static readonly Guid IID = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0xBB, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19);

System.Data.OleDb.OleDbHResult GetSource(out string source);

System.Data.OleDb.OleDbHResult GetDescription(out string description);
}

private class ErrorInfoWrapper : IErrorInfo
{
private readonly IntPtr _wrappedInstance;

public PictureWrapper(IntPtr wrappedInstance)
{
_wrappedInstance = wrappedInstance;
}

public void Dispose()
{
Marshal.Release(_wrappedInstance);
}

public unsafe System.Data.OleDb.OleDbHResult GetSource(out string source)
{
IntPtr pSource;
int errorCode = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 4 /* IErrorInfo.GetSource slot */)))
(_wrappedInstance, &pSource);
if (pSource == IntPtr.Zero)
{
source = null;
}
else
{
source = Marshal.PtrToStringBSTR(pSource);
}

return (System.Data.OleDb.OleDbHResult)errorCode;
}

public unsafe System.Data.OleDb.OleDbHResult GetDescription(out string description)
{
IntPtr pDescription;
int errorCode = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 5 /* IErrorInfo.GetDescription slot */)))
(_wrappedInstance, &pDescription);
if (pDescription == IntPtr.Zero)
{
description = null;
}
else
{
description = Marshal.PtrToStringBSTR(pDescription);
}

return (System.Data.OleDb.OleDbHResult)errorCode;
}
}

}
}
99 changes: 99 additions & 0 deletions src/libraries/System.Data.OleDb/src/OleDbConnection.COMWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;
using System.Data.Common;
using System.Data.ProviderBase;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;

namespace System.Data.OleDb
{
using SysTx = Transactions;

public sealed partial class OleDbConnection
{
internal static Exception? ProcessResults(OleDbHResult hresult, OleDbConnection? connection, object? src)
{
if ((0 <= (int)hresult) && ((null == connection) || (null == connection.Events[EventInfoMessage])))
{
SafeNativeMethods.Wrapper.ClearErrorInfo();
return null;
}

// ErrorInfo object is to be checked regardless the hresult returned by the function called
Exception? e = null;
IntPtr pErrorInfo;
OleDbHResult hr = UnsafeNativeMethods.GetErrorInfo(0, out pErrorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo
if ((OleDbHResult.S_OK == hr) && (null != errorInfo))
{
using OleDbComWrappers.IErrorInfo errorInfo = (OleDbComWrappers.IErrorInfo)OleDbComWrappers.Instance
.GetOrCreateObjectForComInstance(pErrorInfo, CreateObjectFlags.UniqueInstance);;
if (hresult < 0)
{
// 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);
}
}
else if (0 < hresult)
{
// @devnote: OnInfoMessage with no ErrorInfo
}
else if ((int)hresult < 0)
{
e = ODB.NoErrorInformation((null != connection) ? connection.Provider : null, hresult, null); // OleDbException

ResetState(connection);
}
if (null != e)
{
ADP.TraceExceptionAsReturnValue(e);
}
return e;
}

internal void OnInfoMessage(OleDbComWrappers.IErrorInfo errorInfo, OleDbHResult errorCode)
{
OleDbInfoMessageEventHandler? handler = (OleDbInfoMessageEventHandler?)Events[EventInfoMessage];
if (null != handler)
{
try
{
OleDbException exception = OleDbException.CreateException(errorInfo, errorCode, null);
OleDbInfoMessageEventArgs e = new OleDbInfoMessageEventArgs(exception);
handler(this, e);
}
catch (Exception e)
{ // eat the exception
// UNDONE - should not be catching all exceptions!!!
if (!ADP.IsCatchableOrSecurityExceptionType(e))
{
throw;
}

ADP.TraceExceptionWithoutRethrow(e);
}
}
}
}
}
Loading

0 comments on commit b91ee8d

Please sign in to comment.