Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First round of converting System.Data.OleDb to COMWrappers #54822

Merged
merged 38 commits into from
Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b91ee8d
First round of converting System.Data.OleDb to COMWrappers
kant2002 Jun 28, 2021
68ba34e
Update src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
kant2002 Jun 29, 2021
2e0441c
Update src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
kant2002 Jun 29, 2021
2a753ac
Apply PR recommendations
kant2002 Jun 29, 2021
5b7c9dc
Make closer to original
kant2002 Jun 29, 2021
749fee8
One more change
kant2002 Jun 29, 2021
505e6f2
Apply PR feedback
kant2002 Jun 30, 2021
51b3456
Merge remote-tracking branch 'upstream/main' into kant/remove-il2050-…
kant2002 Jun 30, 2021
db65b0b
Update src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj
kant2002 Jun 30, 2021
7e9e956
Update src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj
kant2002 Jun 30, 2021
2cf1788
Fix compilation errors
kant2002 Jun 30, 2021
b928f03
Fix errors
kant2002 Jun 30, 2021
7401706
Consolidate code
kant2002 Jul 1, 2021
5750c8e
Fix compilation warnings
kant2002 Jul 8, 2021
c301fb6
Fix compilation error
kant2002 Jul 8, 2021
5d11dea
Fix compilation error
kant2002 Jul 9, 2021
a1189fd
Address PR feedback
kant2002 Jul 12, 2021
0e12c02
Update PR feedback
kant2002 Jul 12, 2021
0364575
Address PR feedback
kant2002 Jul 19, 2021
a2bbb45
Direct cast
kant2002 Jul 19, 2021
26859c5
Ask wrapper to implement IDisposable
kant2002 Sep 8, 2021
2c6d072
Merge branch 'main' into kant/remove-il2050-oledb
kant2002 Sep 8, 2021
0e1177f
Update src/libraries/System.Data.OleDb/src/OleDbConnection.COMWrapper…
kant2002 Sep 20, 2021
9f3a972
Update src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
kant2002 Sep 20, 2021
f41457f
Update src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
kant2002 Sep 20, 2021
dd9e48a
Update src/libraries/System.Data.OleDb/src/DbPropSet.COMWrappers.cs
kant2002 Sep 20, 2021
adf11e5
Restore changes in OnInfoMessage
kant2002 Sep 20, 2021
27a857b
Consolidate different part of code
kant2002 Sep 20, 2021
eca9732
Remove junk (probably from merge)
kant2002 Sep 20, 2021
76b3032
Found that last commit was a mess
kant2002 Sep 20, 2021
75567c2
Remove no longer needed annotations
kant2002 Sep 20, 2021
3c66ce7
Apply suggestions from code review
kant2002 Sep 21, 2021
af6d01e
Update src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
kant2002 Sep 21, 2021
ed5e796
Free BSTR
kant2002 Sep 21, 2021
c897950
Remove reference to no longer used files in this PR
kant2002 Sep 21, 2021
a331a8e
Add data
kant2002 Sep 21, 2021
e6efd5c
Fix compilation errors
kant2002 Sep 21, 2021
93b8fd3
Last blow to compiler
kant2002 Sep 21, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, &pErrorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo
if ((errorInfoHr == OleDbHResult.S_OK) && (pErrorInfo != IntPtr.Zero))
{
using UnsafeNativeMethods.IErrorInfo errorInfo = (UnsafeNativeMethods.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>
106 changes: 106 additions & 0 deletions src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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;
private static readonly Guid IID_IErrorInfo = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0xBB, 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();
}

private class ErrorInfoWrapper : UnsafeNativeMethods.IErrorInfo
{
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<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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we share the bulk of this code, and only pull out the differences into COMWrappers vs. NoCOMWrappers files? i.e. create new private methods on the partial classes.

{
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, &pErrorInfo); // 0 - IErrorInfo exists, 1 - no IErrorInfo
if ((OleDbHResult.S_OK == hr) && (null != errorInfo))
{
using UnsafeNativeMethods.IErrorInfo errorInfo = (UnsafeNativeMethods.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(UnsafeNativeMethods.IErrorInfo errorInfo, OleDbHResult errorCode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a difference in the code of OnInfoMessage between the COMWrappers file and the NoCOMWrappers file. Why do we need them split?

{
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