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 31 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
12 changes: 10 additions & 2 deletions src/libraries/System.Data.OleDb/src/DbPropSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
29 changes: 3 additions & 26 deletions src/libraries/System.Data.OleDb/src/ILLink/ILLink.Suppressions.xml
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 @@ -102,5 +78,6 @@
<argument>IL2111</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.OleDb.OleDbDataReader.BuildSchemaTable(System.Data.OleDb.MetaData[])</property>
</attribute> </assembly>
</linker>
</attribute>
</assembly>
</linker>
107 changes: 107 additions & 0 deletions src/libraries/System.Data.OleDb/src/OleDbComWrappers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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
{
/// <summary>
/// The ComWrappers implementation for System.Data.OleDb's COM interop usages.
///
/// Supports IErrorInfo COM interface.
/// </summary>
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();
}

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<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 4 /* IErrorInfo.GetSource slot */)))
(_wrappedInstance, &pSource);
if (pSource == IntPtr.Zero || errorCode < 0)
{
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 = IntPtr.Zero;
int errorCode = ((delegate* unmanaged<IntPtr, IntPtr*, int>)(*(*(void***)_wrappedInstance + 5 /* IErrorInfo.GetDescription slot */)))
(_wrappedInstance, &pDescription);
if (pDescription == IntPtr.Zero || errorCode < 0)
{
description = null;
}
else
{
description = Marshal.PtrToStringBSTR(pDescription);
}

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

}
}
45 changes: 24 additions & 21 deletions src/libraries/System.Data.OleDb/src/OleDbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace System.Data.OleDb
// it won't happen if you directly create the provider and set its properties
// 3. First call on IDBInitialize must be Initialize, can't QI for any other interfaces before that
[DefaultEvent("InfoMessage")]
public sealed partial class OleDbConnection : DbConnection, ICloneable, IDbConnection
public sealed class OleDbConnection : DbConnection, ICloneable, IDbConnection
{
private static readonly object EventInfoMessage = new object();

Expand Down Expand Up @@ -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)
{
Expand Down
6 changes: 2 additions & 4 deletions src/libraries/System.Data.OleDb/src/OleDbDataAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down
9 changes: 2 additions & 7 deletions src/libraries/System.Data.OleDb/src/OleDbException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,8 @@ internal static OleDbException CreateException(UnsafeNativeMethods.IErrorInfo er
string? message = null;
string? source = null;
OleDbHResult hr = 0;

if (null != errorInfo)
Copy link
Member

Choose a reason for hiding this comment

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

Why don't we need a null check here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There discussion about that #54822 (comment)

{
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)
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Data.OleDb/src/OleDb_Util.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions src/libraries/System.Data.OleDb/src/System.Data.OleDb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ System.Data.OleDb.OleDbTransaction</PackageDescription>
<Compile Include="System\Data\ProviderBase\DbReferenceCollection.cs" />
<Compile Include="System\Data\ProviderBase\WrappedIUnknown.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' and '$(TargetsWindows)' == 'true' and $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net5.0'))">
<Compile Include="UnsafeNativeMethods.COMWrappers.cs" />
<Compile Include="OleDbComWrappers.cs" />
<Compile Include="DbPropSet.COMWrappers.cs" />
<Compile Include="OleDbConnection.COMWrappers.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' and '$(TargetsWindows)' == 'true' and !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net5.0'))">
<Compile Include="UnsafeNativeMethods.NoCOMWrappers.cs" />
<Compile Include="DbPropSet.NoCOMWrappers.cs" />
<Compile Include="OleDbConnection.NoCOMWrappers.cs" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Resources\System.Data.OleDb.OleDbMetaData.xml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

namespace System.Data.Common
{
internal static partial class UnsafeNativeMethods
{
//
// Oleaut32
//

[DllImport(Interop.Libraries.OleAut32)]
internal static unsafe extern System.Data.OleDb.OleDbHResult GetErrorInfo(
int dwReserved,
System.IntPtr* ppIErrorInfo);

internal static extern System.Data.OleDb.OleDbHResult GetErrorInfo(
int dwReserved,
out UnsafeNativeMethods.IErrorInfo? ppIErrorInfo)
{
ppIErrorInfo = null;
var hr = GetErrorInfo(dwReserved, out IntPtr pErrorInfo);
if (hr == OleDbHResult.S_OK)
{
ppIErrorInfo = (UnsafeNativeMethods.IErrorInfo)OleDbComWrappers.Instance
.GetOrCreateObjectForComInstance(pErrorInfo, CreateObjectFlags.UniqueInstance);
}
}

internal static void ReleaseErrorInfoObject(UnsafeNativeMethods.IErrorInfo errorInfo)
{
((IDisposable)errorInfo).Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

namespace System.Data.Common
{
internal static partial class UnsafeNativeMethods
{
//
// Oleaut32
//

[DllImport(Interop.Libraries.OleAut32, CharSet = CharSet.Unicode, PreserveSig = true)]
internal static extern System.Data.OleDb.OleDbHResult GetErrorInfo(
[In] int dwReserved,
[Out, MarshalAs(UnmanagedType.Interface)] out UnsafeNativeMethods.IErrorInfo? ppIErrorInfo);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
[In] int dwReserved,
[Out, MarshalAs(UnmanagedType.Interface)] out UnsafeNativeMethods.IErrorInfo? ppIErrorInfo);
int dwReserved,
[MarshalAs(UnmanagedType.Interface)] out UnsafeNativeMethods.IErrorInfo? ppIErrorInfo);


internal static void ReleaseErrorInfoObject(UnsafeNativeMethods.IErrorInfo errorInfo)
{
Marshal.ReleaseComObject(errorInfo);
}
}
}
11 changes: 3 additions & 8 deletions src/libraries/System.Data.OleDb/src/UnsafeNativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@

namespace System.Data.Common
{
internal static class UnsafeNativeMethods
internal static partial class UnsafeNativeMethods
{
//
// Oleaut32
//

[DllImport(Interop.Libraries.OleAut32, CharSet = CharSet.Unicode, PreserveSig = true)]
internal static extern System.Data.OleDb.OleDbHResult GetErrorInfo(
[In] int dwReserved,
[Out, MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo);

[Guid("00000567-0000-0010-8000-00AA006D2EA4"), InterfaceType(ComInterfaceType.InterfaceIsDual), ComImport, SuppressUnmanagedCodeSecurity]
internal interface ADORecordConstruction
{
Expand Down Expand Up @@ -518,11 +513,11 @@ internal interface IErrorInfo

[PreserveSig]
System.Data.OleDb.OleDbHResult GetSource(
[Out, MarshalAs(UnmanagedType.BStr)] out string pBstrSource);
[Out, MarshalAs(UnmanagedType.BStr)] out string? pBstrSource);

[PreserveSig]
System.Data.OleDb.OleDbHResult GetDescription(
[Out, MarshalAs(UnmanagedType.BStr)] out string pBstrDescription);
[Out, MarshalAs(UnmanagedType.BStr)] out string? pBstrDescription);

//[ Obsolete("not used", true)] void GetHelpFile(/*deleted parameter signature*/);

Expand Down