Move System.Transactions.Local over to using source-generated COM instead of built...
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Mon, 12 Jun 2023 18:08:06 +0000 (11:08 -0700)
committerGitHub <noreply@github.com>
Mon, 12 Jun 2023 18:08:06 +0000 (11:08 -0700)
Co-authored-by: Shay Rojansky <roji@roji.org>
37 files changed:
src/libraries/System.Transactions.Local/System.Transactions.Local.sln
src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/IPrepareInfo.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/IResourceManager.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/IResourceManagerFactory2.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/IResourceManagerSink.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITmNodeName.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionCloner.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionDispenser.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionEnlistmentAsync.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionExport.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionExportFactory.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionImport.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionImportWhereabouts.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionOptions.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionOutcomeEvents.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionPhase0EnlistmentAsync.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionPhase0Factory.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionPhase0NotifyAsync.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionReceiver.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionReceiverFactory.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionResourceAsync.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionTransmitter.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionTransmitterFactory.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionVoterBallotAsync2.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionVoterFactory2.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcInterfaces/ITransactionVoterNotifyAsync2.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/DtcProxyShimFactory.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/EnlistmentNotifyShim.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/NativeEnums.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/Phase0NotifyShim.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/ResourceManagerNotifyShim.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/TransactionShim.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/VoterNotifyShim.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DtcProxyShim/Xactopt.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs

index 6f3c8b9..38eaab6 100644 (file)
@@ -1,4 +1,8 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.7.33711.456
+MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{B67D04B7-C5ED-44ED-8DB3-8AD788232A5C}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections", "..\System.Collections\ref\System.Collections.csproj", "{6D254833-6EC5-4E3E-96CE-1D97CD66B35F}"
@@ -25,6 +29,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{2ECC9D1A-2EF
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9D6D84CE-3891-482B-B7C0-0089CF93CF45}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComInterfaceGenerator", "..\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj", "{75D2D615-58E5-41BB-9C57-FFC2F01B4931}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -67,20 +73,25 @@ Global
                {C5519C4C-69AF-4437-8594-D2A019119988}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {C5519C4C-69AF-4437-8594-D2A019119988}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {C5519C4C-69AF-4437-8594-D2A019119988}.Release|Any CPU.Build.0 = Release|Any CPU
+               {75D2D615-58E5-41BB-9C57-FFC2F01B4931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {75D2D615-58E5-41BB-9C57-FFC2F01B4931}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {75D2D615-58E5-41BB-9C57-FFC2F01B4931}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {75D2D615-58E5-41BB-9C57-FFC2F01B4931}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
        EndGlobalSection
        GlobalSection(NestedProjects) = preSolution
                {B67D04B7-C5ED-44ED-8DB3-8AD788232A5C} = {E66BBFB5-F07D-4986-89C0-F0E395DD5BA1}
-               {C5519C4C-69AF-4437-8594-D2A019119988} = {E66BBFB5-F07D-4986-89C0-F0E395DD5BA1}
                {6D254833-6EC5-4E3E-96CE-1D97CD66B35F} = {B4E1F144-E017-4E02-8320-DB7467E42BF8}
+               {2A01A433-50B7-4CFA-AA76-CB51971535BB} = {2ECC9D1A-2EF1-4411-98D1-AFFCDAAF9D05}
+               {193FBAA0-BAE2-484A-BB0E-1ADDDC810FC9} = {2ECC9D1A-2EF1-4411-98D1-AFFCDAAF9D05}
                {8D9731A5-CB30-4AAA-9A3B-9C937352623F} = {B4E1F144-E017-4E02-8320-DB7467E42BF8}
                {7CC8FC26-F825-4B5D-9E38-6CE8382BEEAC} = {B4E1F144-E017-4E02-8320-DB7467E42BF8}
                {0C886713-72D7-43C7-A1BB-72CD0F8430D2} = {B4E1F144-E017-4E02-8320-DB7467E42BF8}
-               {2A01A433-50B7-4CFA-AA76-CB51971535BB} = {2ECC9D1A-2EF1-4411-98D1-AFFCDAAF9D05}
-               {193FBAA0-BAE2-484A-BB0E-1ADDDC810FC9} = {2ECC9D1A-2EF1-4411-98D1-AFFCDAAF9D05}
                {6BFF19CB-C412-4D12-AA55-68D61F69C4F7} = {9D6D84CE-3891-482B-B7C0-0089CF93CF45}
+               {C5519C4C-69AF-4437-8594-D2A019119988} = {E66BBFB5-F07D-4986-89C0-F0E395DD5BA1}
+               {75D2D615-58E5-41BB-9C57-FFC2F01B4931} = {2ECC9D1A-2EF1-4411-98D1-AFFCDAAF9D05}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {197B13C9-4EA6-408B-8EF6-B551B2A58A89}
index 78e7ed3..5a7cc44 100644 (file)
@@ -3,7 +3,7 @@
     <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)</TargetFrameworks>
-    <NoWarn>CA1805;IDE0059;CS1591</NoWarn>
+    <NoWarn>CA1805;IDE0059;CS1591;CS3016</NoWarn>
     <TargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))</TargetPlatformIdentifier>
   </PropertyGroup>
   <ItemGroup>
@@ -44,6 +44,7 @@
   </ItemGroup>
   <ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'windows'">
     <Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs" Link="Common\Interop\Windows\Interop.Libraries.cs" />
+    <Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs" Link="Common\DisableRuntimeMarshalling.cs" />
     <Compile Include="System\Transactions\DtcProxyShim\DtcInterfaces\IPrepareInfo.cs" />
     <Compile Include="System\Transactions\DtcProxyShim\DtcInterfaces\IResourceManagerFactory2.cs" />
     <Compile Include="System\Transactions\DtcProxyShim\DtcInterfaces\IResourceManager.cs" />
     <Reference Include="System.Threading.ThreadPool" />
     <Reference Include="System.Xml.ReaderWriter" />
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\System.Runtime.InteropServices\gen\ComInterfaceGenerator\ComInterfaceGenerator.csproj" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
+  </ItemGroup>
 </Project>
index 576f55f..70a23d2 100644 (file)
@@ -2,14 +2,15 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686533(v=vs.85)
-[ComImport, Guid("80c7bfd0-87ee-11ce-8081-0080c758527e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface IPrepareInfo
+[GeneratedComInterface, Guid("80c7bfd0-87ee-11ce-8081-0080c758527e"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface IPrepareInfo
 {
     void GetPrepareInfoSize(out uint pcbPrepInfo);
 
-    void GetPrepareInfo([MarshalAs(UnmanagedType.LPArray), Out] byte[] pPrepInfo);
+    void GetPrepareInfo([MarshalAs(UnmanagedType.LPArray)] byte[] pPrepInfo);
 }
index 4cec70b..b10be08 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms681790(v=vs.85)
-[ComImport, Guid(Guids.IID_IResourceManager), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface IResourceManager
+[GeneratedComInterface, Guid(Guids.IID_IResourceManager), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface IResourceManager
 {
     internal void Enlist(
         [MarshalAs(UnmanagedType.Interface)] ITransaction pTransaction,
@@ -20,7 +21,7 @@ internal interface IResourceManager
         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pPrepInfo,
         uint cbPrepInfom,
         uint lTimeout,
-        [MarshalAs(UnmanagedType.I4)] out OletxXactStat pXactStat);
+        out OletxXactStat pXactStat);
 
     void ReenlistmentComplete();
 
index dd4777c..e29ed9a 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686489(v=vs.85)
-[ComImport, Guid("6B369C21-FBD2-11d1-8F47-00C04F8EE57D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface IResourceManagerFactory2
+[GeneratedComInterface, Guid("6B369C21-FBD2-11d1-8F47-00C04F8EE57D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface IResourceManagerFactory2
 {
     internal void Create(
         in Guid pguidRM,
index 0e87218..b39510b 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686073(v=vs.85)
-[ComImport, Guid("0D563181-DEFB-11CE-AED1-00AA0051E2C4"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface IResourceManagerSink
+[GeneratedComInterface, Guid("0D563181-DEFB-11CE-AED1-00AA0051E2C4"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface IResourceManagerSink
 {
     void TMDown();
 }
index 4816352..4b6b4df 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms687122(v=vs.85)
-[ComImport, Guid("30274F88-6EE4-474e-9B95-7807BC9EF8CF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITmNodeName
+[GeneratedComInterface, Guid("30274F88-6EE4-474e-9B95-7807BC9EF8CF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITmNodeName
 {
     internal void GetNodeNameSize(out uint pcbNodeNameSize);
 
index de54474..6a16212 100644 (file)
@@ -2,16 +2,17 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686531(v=vs.85)
-[ComImport, Guid(Guids.IID_ITransaction), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransaction
+[GeneratedComInterface, Guid(Guids.IID_ITransaction), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransaction
 {
     void Commit(
         [MarshalAs(UnmanagedType.Bool)] bool fRetaining,
-        [MarshalAs(UnmanagedType.U4)] OletxXacttc grfTC,
+        OletxXacttc grfTC,
         uint grfRM);
 
     void Abort(
index 3090333..3a513b6 100644 (file)
@@ -2,16 +2,17 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms684377(v=vs.85)
-[ComImport, Guid("02656950-2152-11d0-944C-00A0C905416E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionCloner
+[GeneratedComInterface, Guid("02656950-2152-11d0-944C-00A0C905416E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionCloner
 {
     void Commit(
         [MarshalAs(UnmanagedType.Bool)] bool fRetainingt,
-        [MarshalAs(UnmanagedType.U4)] OletxXacttc grfTC,
+        OletxXacttc grfTC,
         uint grfRM);
 
     void Abort(
index d5ca436..8d0a1d7 100644 (file)
@@ -2,21 +2,22 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 using System.Transactions.DtcProxyShim;
 using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms687604(v=vs.85)
-[ComImport, Guid(Guids.IID_ITransactionDispenser), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionDispenser
+[GeneratedComInterface, Guid(Guids.IID_ITransactionDispenser), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionDispenser
 {
     void GetOptionsObject([MarshalAs(UnmanagedType.Interface)] out ITransactionOptions ppOptions);
 
     void BeginTransaction(
         IntPtr punkOuter,
-        [MarshalAs(UnmanagedType.I4)] OletxTransactionIsolationLevel isoLevel,
-        [MarshalAs(UnmanagedType.I4)] OletxTransactionIsoFlags isoFlags,
+        OletxTransactionIsolationLevel isoLevel,
+        OletxTransactionIsoFlags isoFlags,
         [MarshalAs(UnmanagedType.Interface)] ITransactionOptions pOptions,
         [MarshalAs(UnmanagedType.Interface)] out ITransaction ppTransaction);
 }
index 8fb42b4..e5a2d36 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686429(v=vs.85)
-[ComImport, Guid("0fb15081-af41-11ce-bd2b-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionEnlistmentAsync
+[GeneratedComInterface, Guid("0fb15081-af41-11ce-bd2b-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionEnlistmentAsync
 {
     void PrepareRequestDone(int hr, IntPtr pmk, IntPtr pboidReason);
 
index 75b6e7e..7fd2822 100644 (file)
@@ -2,18 +2,19 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms678954(v=vs.85)
-[ComImport, Guid("0141fda5-8fc0-11ce-bd18-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionExport
+[GeneratedComInterface, Guid("0141fda5-8fc0-11ce-bd18-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionExport
 {
     void Export([MarshalAs(UnmanagedType.Interface)] ITransaction punkTransaction, out uint pcbTransactionCookie);
 
     void GetTransactionCookie(
         [MarshalAs(UnmanagedType.Interface)] ITransaction pITransaction,
         uint cbTransactionCookie,
-        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] byte[] rgbTransactionCookie,
+        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] rgbTransactionCookie,
         out uint pcbUsed);
 }
index 0369283..672f457 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686771(v=vs.85)
-[ComImport, Guid("E1CF9B53-8745-11ce-A9BA-00AA006C3706"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionExportFactory
+[GeneratedComInterface, Guid("E1CF9B53-8745-11ce-A9BA-00AA006C3706"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionExportFactory
 {
     void GetRemoteClassId(out Guid pclsid);
 
index a7095a6..57d4656 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms681296(v=vs.85)
-[ComImport, Guid("E1CF9B5A-8745-11ce-A9BA-00AA006C3706"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionImport
+[GeneratedComInterface, Guid("E1CF9B5A-8745-11ce-A9BA-00AA006C3706"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionImport
 {
     void Import(
         uint cbTransactionCookie,
index 28f932e..58b3d2f 100644 (file)
@@ -2,17 +2,18 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms682783(v=vs.85)
-[ComImport, Guid("0141fda4-8fc0-11ce-bd18-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionImportWhereabouts
+[GeneratedComInterface, Guid("0141fda4-8fc0-11ce-bd18-204c4f4f5020"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionImportWhereabouts
 {
     internal void GetWhereaboutsSize(out uint pcbSize);
 
     internal void GetWhereabouts(
         uint cbWhereabouts,
-        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] byte[] rgbWhereabouts,
+        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] rgbWhereabouts,
         out uint pcbUsed);
 }
index 6635861..3a894ec 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686489(v=vs.85)
-[ComImport, Guid("3A6AD9E0-23B9-11cf-AD60-00AA00A74CCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionOptions
+[GeneratedComInterface, Guid("3A6AD9E0-23B9-11cf-AD60-00AA00A74CCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionOptions
 {
     void SetOptions(Xactopt pOptions);
 
index 3627730..6d26bbb 100644 (file)
@@ -2,10 +2,10 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
-using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
+// Keep this type as a ComImport type as it is used with IConnectionPointContainer (and as a result needs to use built-in COM).
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686465(v=vs.85)
 [ComImport, Guid("3A6AD9E2-23B9-11cf-AD60-00AA00A74CCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 internal interface ITransactionOutcomeEvents
@@ -22,7 +22,7 @@ internal interface ITransactionOutcomeEvents
         int hresult);
 
     void HeuristicDecision(
-        [MarshalAs(UnmanagedType.U4)] OletxTransactionHeuristic dwDecision,
+        OletxTransactionHeuristic dwDecision,
         IntPtr pboidReason,
         int hresult);
 
index ca6872f..c77761e 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms685087(v=vs.85).</remarks
-[ComImport, Guid("82DC88E1-A954-11d1-8F88-00600895E7D5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionPhase0EnlistmentAsync
+[GeneratedComInterface, Guid("82DC88E1-A954-11d1-8F88-00600895E7D5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionPhase0EnlistmentAsync
 {
     void Enable();
 
index be02ff6..1fa7150 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms682238(v=vs.85)
-[ComImport, Guid("82DC88E0-A954-11d1-8F88-00600895E7D5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionPhase0Factory
+[GeneratedComInterface, Guid("82DC88E0-A954-11d1-8F88-00600895E7D5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionPhase0Factory
 {
     void Create(
         [MarshalAs(UnmanagedType.Interface)] ITransactionPhase0NotifyAsync pITransactionPhase0Notify,
index 010e49d..973a104 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686106(v=vs.85)
-[ComImport, Guid("EF081809-0C76-11d2-87A6-00C04F990F34"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionPhase0NotifyAsync
+[GeneratedComInterface, Guid("EF081809-0C76-11d2-87A6-00C04F990F34"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionPhase0NotifyAsync
 {
     void Phase0Request([MarshalAs(UnmanagedType.Bool)] bool fAbortHint);
 
index 1b1f388..de9fbd0 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms679193(v=vs.85)
-[ComImport, Guid("59313E03-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionReceiver
+[GeneratedComInterface, Guid("59313E03-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionReceiver
 {
     void UnmarshalPropagationToken(
         uint cbToken,
@@ -18,7 +19,7 @@ internal interface ITransactionReceiver
 
     void MarshalReturnToken(
         uint cbReturnToken,
-        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] out byte[] rgbReturnToken,
+        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out byte[] rgbReturnToken,
         out uint pcbUsed);
 
     void Reset();
index 8a29e99..27f8505 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms683577(v=vs.85)
-[ComImport, Guid("59313E02-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionReceiverFactory
+[GeneratedComInterface, Guid("59313E02-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionReceiverFactory
 {
     void Create([MarshalAs(UnmanagedType.Interface)] out ITransactionReceiver pTxReceiver);
 }
index 79489c6..cc85c36 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms678823(v=vs.85)
-[ComImport, Guid("69E971F0-23CE-11cf-AD60-00AA00A74CCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionResourceAsync
+[GeneratedComInterface, Guid("69E971F0-23CE-11cf-AD60-00AA00A74CCD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionResourceAsync
 {
     void PrepareRequest(
         [MarshalAs(UnmanagedType.Bool)] bool fRetaining,
index e00cba9..1ad4a01 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms682296(v=vs.85)
-[ComImport, Guid("59313E01-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionTransmitter
+[GeneratedComInterface, Guid("59313E01-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionTransmitter
 {
     void Set([MarshalAs(UnmanagedType.Interface)] ITransaction transaction);
 
@@ -15,7 +16,7 @@ internal interface ITransactionTransmitter
 
     void MarshalPropagationToken(
         uint cbToken,
-        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0), Out] byte[] rgbToken,
+        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] byte[] rgbToken,
         out uint pcbUsed);
 
     void UnmarshalReturnToken(
index 9179778..961bcaa 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms679232(v=vs.85)
-[ComImport, Guid("59313E00-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionTransmitterFactory
+[GeneratedComInterface, Guid("59313E00-B36C-11cf-A539-00AA006887C3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionTransmitterFactory
 {
     void Create([MarshalAs(UnmanagedType.Interface)] out ITransactionTransmitter pTxTransmitter);
 }
index f4e77a9..d4ac7ea 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms680565(v=vs.85)
-[ComImport, Guid("5433376C-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionVoterBallotAsync2
+[GeneratedComInterface, Guid("5433376C-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionVoterBallotAsync2
 {
     void VoteRequestDone(int hr, IntPtr pboidReason);
 }
index c1fdfcb..2d254f9 100644 (file)
@@ -2,12 +2,13 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms686084(v=vs.85)
-[ComImport, Guid("5433376A-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionVoterFactory2
+[GeneratedComInterface, Guid("5433376A-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionVoterFactory2
 {
     void Create(
         [MarshalAs(UnmanagedType.Interface)] ITransaction pITransaction,
index 9fb0abb..ed4d9f9 100644 (file)
@@ -2,13 +2,14 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim.DtcInterfaces;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms678930(v=vs.85)
-[ComImport, Guid("5433376B-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
-internal interface ITransactionVoterNotifyAsync2
+[GeneratedComInterface, Guid("5433376B-414D-11d3-B206-00C04FC2F3EF"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+internal partial interface ITransactionVoterNotifyAsync2
 {
     void Committed(
         [MarshalAs(UnmanagedType.Bool)] bool fRetaining,
@@ -22,7 +23,7 @@ internal interface ITransactionVoterNotifyAsync2
         uint hresult);
 
     void HeuristicDecision(
-        [MarshalAs(UnmanagedType.U4)] OletxTransactionHeuristic dwDecision,
+        OletxTransactionHeuristic dwDecision,
         IntPtr pboidReason,
         uint hresult);
 
index 2ec9b30..8400cad 100644 (file)
@@ -12,7 +12,7 @@ using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim;
 
-internal sealed class DtcProxyShimFactory
+internal sealed partial class DtcProxyShimFactory
 {
     // Used to synchronize access to the proxy.  This is necessary in
     // initialization because the proxy doesn't like multiple simultaneous callers
@@ -45,19 +45,18 @@ internal sealed class DtcProxyShimFactory
         => _eventHandle = notificationEventHandle;
 
     // https://docs.microsoft.com/previous-versions/windows/desktop/ms678898(v=vs.85)
-    [DllImport(Interop.Libraries.Xolehlp, CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
+    [LibraryImport(Interop.Libraries.Xolehlp, StringMarshalling = StringMarshalling.Utf16)]
     [RequiresUnreferencedCode(TransactionManager.DistributedTransactionTrimmingWarning)]
-    private static extern void DtcGetTransactionManagerExW(
+    private static unsafe partial int DtcGetTransactionManagerExW(
         [MarshalAs(UnmanagedType.LPWStr)] string? pszHost,
         [MarshalAs(UnmanagedType.LPWStr)] string? pszTmName,
         in Guid riid,
         int grfOptions,
-        object? pvConfigPararms,
+        void* pvConfigPararms,
         [MarshalAs(UnmanagedType.Interface)] out ITransactionDispenser ppvObject);
 
     [RequiresUnreferencedCode(TransactionManager.DistributedTransactionTrimmingWarning)]
-    private static void DtcGetTransactionManager(string? nodeName, out ITransactionDispenser localDispenser) =>
-        DtcGetTransactionManagerExW(nodeName, null, Guids.IID_ITransactionDispenser_Guid, 0, null, out localDispenser);
+    private static unsafe void DtcGetTransactionManager(string? nodeName, out ITransactionDispenser localDispenser) => Marshal.ThrowExceptionForHR(DtcGetTransactionManagerExW(nodeName, null, Guids.IID_ITransactionDispenser_Guid, 0, null, out localDispenser));
 
     public void ConnectToProxy(
         string? nodeName,
@@ -329,7 +328,7 @@ internal sealed class DtcProxyShimFactory
         transaction.GetTransactionInfo(out OletxXactTransInfo xactInfo);
 
         // Register for outcome events.
-        var pContainer = (IConnectionPointContainer)transaction;
+        var pContainer = (IConnectionPointContainer)TransactionInterop.GetDtcTransaction(transaction);
         var guid = Guids.IID_ITransactionOutcomeEvents_Guid;
         pContainer.FindConnectionPoint(ref guid, out IConnectionPoint? pConnPoint);
         pConnPoint!.Advise(transactionNotifyShim, out int connPointCookie);
index b8f46ce..ad3beff 100644 (file)
@@ -2,13 +2,15 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System;
+using System.Runtime.InteropServices.Marshalling;
 using System.Threading;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
 using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim;
 
-internal sealed class EnlistmentNotifyShim : NotificationShimBase, ITransactionResourceAsync
+[GeneratedComClass]
+internal sealed partial class EnlistmentNotifyShim : NotificationShimBase, ITransactionResourceAsync
 {
     internal ITransactionEnlistmentAsync? EnlistmentAsync;
 
index f852af7..a8e7de4 100644 (file)
@@ -115,7 +115,7 @@ internal enum OletxTransactionHeuristic : uint
     XACTHEURISTIC_DANGER = 4
 }
 
-internal enum OletxXactStat
+internal enum OletxXactStat : int
 {
     XACTSTAT_NONE = 0,
     XACTSTAT_OPENNORMAL = 0x1,
index dc2d192..4676b7a 100644 (file)
@@ -1,12 +1,14 @@
 // 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.Marshalling;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
 using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim;
 
-internal sealed class Phase0NotifyShim : NotificationShimBase, ITransactionPhase0NotifyAsync
+[GeneratedComClass]
+internal sealed partial class Phase0NotifyShim : NotificationShimBase, ITransactionPhase0NotifyAsync
 {
     internal Phase0NotifyShim(DtcProxyShimFactory shimFactory, object enlistmentIdentifier)
         : base(shimFactory, enlistmentIdentifier)
index 53ac780..edeeac1 100644 (file)
@@ -3,10 +3,12 @@
 
 using System.Transactions.Oletx;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace System.Transactions.DtcProxyShim;
 
-internal sealed class ResourceManagerNotifyShim : NotificationShimBase, IResourceManagerSink
+[GeneratedComClass]
+internal sealed partial class ResourceManagerNotifyShim : NotificationShimBase, IResourceManagerSink
 {
     internal ResourceManagerNotifyShim(
         DtcProxyShimFactory shimFactory,
index 0c428d6..741b997 100644 (file)
@@ -1,6 +1,8 @@
 // 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;
+using System.Runtime.InteropServices.Marshalling;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
 using System.Transactions.Oletx;
 
@@ -52,12 +54,12 @@ internal sealed class TransactionShim
         cookieBuffer = buffer;
     }
 
-    public void GetITransactionNative(out IDtcTransaction transactionNative)
+    public void GetITransactionNative(out ITransaction transactionNative)
     {
         var cloner = (ITransactionCloner)Transaction;
         cloner.CloneWithCommitDisabled(out ITransaction returnTransaction);
 
-        transactionNative = (IDtcTransaction)returnTransaction;
+        transactionNative = returnTransaction;
     }
 
     public unsafe byte[] GetPropagationToken()
index fad9958..206795f 100644 (file)
@@ -2,12 +2,14 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
 using System.Transactions.Oletx;
 
 namespace System.Transactions.DtcProxyShim;
 
-internal sealed class VoterNotifyShim : NotificationShimBase, ITransactionVoterNotifyAsync2
+[GeneratedComClass]
+internal sealed partial class VoterNotifyShim : NotificationShimBase, ITransactionVoterNotifyAsync2
 {
     internal VoterNotifyShim(DtcProxyShimFactory shimFactory, object enlistmentIdentifier)
         : base(shimFactory, enlistmentIdentifier)
index 2f6bac5..338df45 100644 (file)
@@ -1,12 +1,14 @@
 // 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.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
+using System.Text;
 
 namespace System.Transactions.DtcProxyShim;
 
 // https://docs.microsoft.com/previous-versions/windows/desktop/ms679195(v=vs.85)
+[NativeMarshalling(typeof(Marshaller))]
 [StructLayout(LayoutKind.Sequential)]
 internal struct Xactopt
 {
@@ -17,4 +19,32 @@ internal struct Xactopt
 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
     public string SzDescription;
+
+    [CustomMarshaller(typeof(Xactopt), MarshalMode.ManagedToUnmanagedIn, typeof(Marshaller))]
+    [CustomMarshaller(typeof(Xactopt), MarshalMode.UnmanagedToManagedIn, typeof(Marshaller))]
+    internal static class Marshaller
+    {
+        internal unsafe struct XactoptNative
+        {
+            public uint UlTimeout;
+
+            public fixed byte SzDescription[40];
+        }
+
+        public static unsafe XactoptNative ConvertToUnmanaged(Xactopt managed)
+        {
+            XactoptNative native = new()
+            {
+                UlTimeout = managed.UlTimeout,
+            };
+
+            // Usage of Xactopt never passes non-ASCII chars, so we can ignore them.
+            Encoding.ASCII.TryGetBytes(managed.SzDescription, new Span<byte>(native.SzDescription, 40), out _);
+
+            return native;
+        }
+
+        public static unsafe Xactopt ConvertToManaged(XactoptNative unmanaged)
+        => new(unmanaged.UlTimeout, Encoding.ASCII.GetString(unmanaged.SzDescription, 40));
+    }
 }
index e2da43f..3c5ecb5 100644 (file)
@@ -3,6 +3,7 @@
 
 using System.Diagnostics;
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 using System.Transactions.DtcProxyShim;
 using System.Transactions.DtcProxyShim.DtcInterfaces;
 using System.Transactions.Oletx;
@@ -278,14 +279,21 @@ namespace System.Transactions
                 etwLog.MethodEnter(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetDtcTransaction)}");
             }
 
-            IDtcTransaction? transactionNative;
+            IDtcTransaction? transactionComObject;
 
             // First, make sure we are working with an OletxTransaction.
             OletxTransaction oletxTx = ConvertToOletxTransaction(transaction);
 
             try
             {
-                oletxTx.RealOletxTransaction.TransactionShim.GetITransactionNative(out transactionNative);
+                oletxTx.RealOletxTransaction.TransactionShim.GetITransactionNative(out ITransaction transactionNative);
+
+                ComWrappers.TryGetComInstance(transactionNative, out IntPtr transactionNativePtr);
+
+                transactionComObject = (IDtcTransaction)Marshal.GetObjectForIUnknown(transactionNativePtr);
+                Marshal.SetComObjectData(transactionComObject, typeof(ITransaction), transactionNative);
+
+                Marshal.Release(transactionNativePtr);
             }
             catch (COMException comException)
             {
@@ -298,6 +306,17 @@ namespace System.Transactions
                 etwLog.MethodExit(TraceSourceType.TraceSourceOleTx, $"{nameof(TransactionInterop)}.{nameof(GetDtcTransaction)}");
             }
 
+            return transactionComObject;
+        }
+
+        internal static IDtcTransaction GetDtcTransaction(ITransaction transaction)
+        {
+            ComWrappers.TryGetComInstance(transaction, out IntPtr transactionNativePtr);
+
+            var transactionNative = (IDtcTransaction)Marshal.GetObjectForIUnknown(transactionNativePtr);
+            Marshal.SetComObjectData(transactionNative, typeof(ITransaction), transaction);
+
+            Marshal.Release(transactionNativePtr);
             return transactionNative;
         }
 
@@ -320,12 +339,9 @@ namespace System.Transactions
             RealOletxTransaction? realTx = null;
             OletxTransaction? oleTx = null;
 
-            // Let's get the guid of the transaction from the proxy to see if we already have an object.
-            if (transactionNative is not ITransaction myTransactionNative)
-            {
-                throw new ArgumentException(SR.InvalidArgument, nameof(transactionNative));
-            }
+            ITransaction myTransactionNative = GetITransactionFromIDtcTransaction(transactionNative);
 
+            // Let's get the guid of the transaction from the proxy to see if we already have an object.
             OletxXactTransInfo xactInfo;
             try
             {
@@ -419,6 +435,32 @@ namespace System.Transactions
             return transaction;
         }
 
+        internal static ITransaction GetITransactionFromIDtcTransaction(IDtcTransaction transactionNative)
+        {
+            if (Marshal.GetComObjectData(transactionNative, typeof(ITransaction)) is not ITransaction myTransactionNative)
+            {
+                unsafe
+                {
+                    nint unknown = Marshal.GetIUnknownForObject(transactionNative);
+                    Guid iid = Guids.IID_ITransaction_Guid;
+                    if (Marshal.QueryInterface(unknown, ref iid, out IntPtr transactionNativePtr) == 0)
+                    {
+                        Marshal.Release(unknown);
+                        myTransactionNative = ComInterfaceMarshaller<ITransaction>.ConvertToManaged((void*)transactionNativePtr)!;
+                        Marshal.SetComObjectData(transactionNative, typeof(ITransaction), myTransactionNative);
+                        Marshal.Release(transactionNativePtr);
+                    }
+                    else
+                    {
+                        Marshal.Release(unknown);
+                        throw new ArgumentException(SR.InvalidArgument, nameof(transactionNative));
+                    }
+                }
+            }
+
+            return myTransactionNative;
+        }
+
         public static byte[] GetWhereabouts()
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;