diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index bb6a670802c733..e98daf39526500 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -117,6 +117,7 @@ The PR that reveals the implementation of the ` are obsolete. Use the new ones that take an IComparer\. | | __`SYSLIB0062`__ | XSLT Script blocks are not supported. | +| __`SYSLIB0063`__ | This constructor has been deprecated and argument bool isConnected does not have any effect. Use NamedPipeClientStream(PipeDirection direction, bool isAsync, SafePipeHandle safePipeHandle) instead. | ## Analyzer Warnings diff --git a/src/libraries/Common/src/System/Obsoletions.cs b/src/libraries/Common/src/System/Obsoletions.cs index 45a552749a9614..81756105c26fda 100644 --- a/src/libraries/Common/src/System/Obsoletions.cs +++ b/src/libraries/Common/src/System/Obsoletions.cs @@ -198,6 +198,9 @@ internal static class Obsoletions internal const string XsltSettingsEnableScriptMessage = "XSLT Script blocks are not supported."; internal const string XsltSettingsEnableScriptDiagId = "SYSLIB0062"; + internal const string NamedPipeClientStreamIsConnectedMessage = "This constructor has been deprecated and argument bool isConnected does not have any effect. Use NamedPipeClientStream(PipeDirection direction, bool isAsync, SafePipeHandle safePipeHandle) instead."; + internal const string NamedPipeClientStreamIsConnectedDiagId = "SYSLIB0063"; + // When adding a new diagnostic ID, add it to the table in docs\project\list-of-diagnostics.md as well. // Keep new const identifiers above this comment. } diff --git a/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs b/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs index 85387dbbd4b635..f037bc7b2b4cc1 100644 --- a/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs +++ b/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs @@ -42,7 +42,10 @@ public void DisposeLocalCopyOfClientHandle() { } } public sealed partial class NamedPipeClientStream : System.IO.Pipes.PipeStream { + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This constructor has been deprecated and argument bool isConnected does not have any effect. Use NamedPipeClientStream(PipeDirection direction, bool isAsync, SafePipeHandle safePipeHandle) instead.", DiagnosticId = "SYSLIB0063", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public NamedPipeClientStream(System.IO.Pipes.PipeDirection direction, bool isAsync, bool isConnected, Microsoft.Win32.SafeHandles.SafePipeHandle safePipeHandle) : base (default(System.IO.Pipes.PipeDirection), default(int)) { } + public NamedPipeClientStream(System.IO.Pipes.PipeDirection direction, bool isAsync, Microsoft.Win32.SafeHandles.SafePipeHandle safePipeHandle) : base (default(System.IO.Pipes.PipeDirection), default(int)) { } public NamedPipeClientStream(string pipeName) : base (default(System.IO.Pipes.PipeDirection), default(int)) { } public NamedPipeClientStream(string serverName, string pipeName) : base (default(System.IO.Pipes.PipeDirection), default(int)) { } [System.Runtime.Versioning.SupportedOSPlatformAttribute("windows")] diff --git a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj index af23701a5adb30..c8fed74be3fbc6 100644 --- a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj +++ b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj @@ -27,6 +27,8 @@ + diff --git a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs index 26db5533031718..29937a161d4b55 100644 --- a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs +++ b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs @@ -1,6 +1,7 @@ // 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.Diagnostics; using System.Security; using System.Security.Principal; @@ -88,8 +89,14 @@ public NamedPipeClientStream(string serverName, string pipeName, PipeDirection d _accessRights = AccessRightsFromDirection(direction); } - // Create a NamedPipeClientStream from an existing server pipe handle. + [Obsolete(Obsoletions.NamedPipeClientStreamIsConnectedMessage, DiagnosticId = Obsoletions.NamedPipeClientStreamIsConnectedDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] + [EditorBrowsable(EditorBrowsableState.Never)] public NamedPipeClientStream(PipeDirection direction, bool isAsync, bool isConnected, SafePipeHandle safePipeHandle) + : this(direction, isAsync, safePipeHandle) + { + } + + public NamedPipeClientStream(PipeDirection direction, bool isAsync, SafePipeHandle safePipeHandle) : base(direction, 0) { ArgumentNullException.ThrowIfNull(safePipeHandle); @@ -101,10 +108,7 @@ public NamedPipeClientStream(PipeDirection direction, bool isAsync, bool isConne ValidateHandleIsPipe(safePipeHandle); InitializeHandle(safePipeHandle, true, isAsync); - if (isConnected) - { - State = PipeState.Connected; - } + State = PipeState.Connected; } ~NamedPipeClientStream() diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs index 5b164b849fac3c..419a701392c6be 100644 --- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs +++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Security.Principal; +using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; using Xunit; @@ -99,7 +100,10 @@ public static void InvalidImpersonationLevel_Throws_ArgumentOutOfRangeException( [InlineData(PipeDirection.Out)] public static void NullHandle_Throws_ArgumentNullException(PipeDirection direction) { +#pragma warning disable SYSLIB0063 // Testing the obsolete constructor AssertExtensions.Throws("safePipeHandle", () => new NamedPipeClientStream(direction, false, true, null)); +#pragma warning restore SYSLIB0063 + AssertExtensions.Throws("safePipeHandle", () => new NamedPipeClientStream(direction, false, null)); } [Theory] @@ -109,7 +113,10 @@ public static void NullHandle_Throws_ArgumentNullException(PipeDirection directi public static void InvalidHandle_Throws_ArgumentException(PipeDirection direction) { using SafePipeHandle pipeHandle = new SafePipeHandle(new IntPtr(-1), true); +#pragma warning disable SYSLIB0063 // Testing the obsolete constructor AssertExtensions.Throws("safePipeHandle", () => new NamedPipeClientStream(direction, false, true, pipeHandle)); +#pragma warning restore SYSLIB0063 + AssertExtensions.Throws("safePipeHandle", () => new NamedPipeClientStream(direction, false, pipeHandle)); } [Theory] @@ -129,7 +136,10 @@ public static void BadHandleKind_Throws_IOException(PipeDirection direction) IntPtr handle = safeHandle.DangerousGetHandle(); SafePipeHandle fakePipeHandle = new SafePipeHandle(handle, ownsHandle: false); +#pragma warning disable SYSLIB0063 // Testing the obsolete constructor Assert.Throws(() => new NamedPipeClientStream(direction, false, true, fakePipeHandle)); +#pragma warning restore SYSLIB0063 + Assert.Throws(() => new NamedPipeClientStream(direction, false, fakePipeHandle)); } finally { @@ -145,5 +155,46 @@ public static void NamedPipeClientStream_InvalidHandleInerhitability() AssertExtensions.Throws("inheritability", () => new NamedPipeClientStream("a", "b", PipeDirection.Out, 0, TokenImpersonationLevel.Delegation, HandleInheritability.None - 1)); AssertExtensions.Throws("inheritability", () => new NamedPipeClientStream("a", "b", PipeDirection.Out, 0, TokenImpersonationLevel.Delegation, HandleInheritability.Inheritable + 1)); } + + [Fact] + public static async Task ConnectOnPipeFromExistingHandle_Throws_InvalidOperationException() + { + string pipeName = PipeStreamConformanceTests.GetUniquePipeName(); + + using (var server1 = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 3, PipeTransmissionMode.Byte, PipeOptions.None)) + using (var client1 = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None)) + { + client1.Connect(); + server1.WaitForConnection(); + + var clientFromHandle = new NamedPipeClientStream(PipeDirection.InOut, false, client1.SafePipeHandle); + Assert.Throws(clientFromHandle.Connect); + await Assert.ThrowsAsync(clientFromHandle.ConnectAsync); + } + +#pragma warning disable SYSLIB0063 + using (var server2 = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 3, PipeTransmissionMode.Byte, PipeOptions.None)) + using (var client2 = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None)) + { + client2.Connect(); + server2.WaitForConnection(); + + var clientFromHandleTrue = new NamedPipeClientStream(PipeDirection.InOut, isAsync: false, isConnected: true, client2.SafePipeHandle); + Assert.Throws(clientFromHandleTrue.Connect); + await Assert.ThrowsAsync(clientFromHandleTrue.ConnectAsync); + } + + using (var server3 = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 3, PipeTransmissionMode.Byte, PipeOptions.None)) + using (var client3 = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None)) + { + client3.Connect(); + server3.WaitForConnection(); + + var clientFromHandleFalse = new NamedPipeClientStream(PipeDirection.InOut, isAsync: false, isConnected: false, client3.SafePipeHandle); + Assert.Throws(clientFromHandleFalse.Connect); + await Assert.ThrowsAsync(clientFromHandleFalse.ConnectAsync); + } +#pragma warning restore SYSLIB0063 + } } } diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs index e01f42f9d27e58..de94c98b1b0cc1 100644 --- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs +++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs @@ -35,7 +35,7 @@ public void InheritHandles_AvailableInChildProcess() void ChildFunc(string handle) { - using (var childClient = new NamedPipeClientStream(PipeDirection.Out, isAsync: false, isConnected: true, new SafePipeHandle((IntPtr)long.Parse(handle, CultureInfo.InvariantCulture), ownsHandle: true))) + using (var childClient = new NamedPipeClientStream(PipeDirection.Out, isAsync: false, new SafePipeHandle((IntPtr)long.Parse(handle, CultureInfo.InvariantCulture), ownsHandle: true))) { for (int i = 0; i < 5; i++) { diff --git a/src/libraries/System.IO.Pipes/tests/PipeStreamConformanceTests.cs b/src/libraries/System.IO.Pipes/tests/PipeStreamConformanceTests.cs index 918303b019a0a0..867e12206528de 100644 --- a/src/libraries/System.IO.Pipes/tests/PipeStreamConformanceTests.cs +++ b/src/libraries/System.IO.Pipes/tests/PipeStreamConformanceTests.cs @@ -171,7 +171,7 @@ public async Task ClonedClient_ActsAsOriginalClient() if (writeable is NamedPipeServerStream server) { - using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.In, false, true, ((NamedPipeClientStream)readable).SafePipeHandle)) + using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.In, false, ((NamedPipeClientStream)readable).SafePipeHandle)) { if (OperatingSystem.IsWindows()) { @@ -186,7 +186,7 @@ public async Task ClonedClient_ActsAsOriginalClient() } else { - using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.Out, false, true, ((NamedPipeClientStream)writeable).SafePipeHandle)) + using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.Out, false, ((NamedPipeClientStream)writeable).SafePipeHandle)) { Task clientTask = client.WriteAsync(msg1, 0, msg1.Length); int receivedLength = readable.Read(received1, 0, msg1.Length);