diff --git a/Common.sln b/Common.sln index 96da917..60aed0c 100644 --- a/Common.sln +++ b/Common.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27004.2010 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28705.295 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D9798FDE-76F4-4848-8AE0-95249C0101F0}" EndProject @@ -21,6 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution nuget.config = nuget.config README.md = README.md stylecop.json = stylecop.json + targetframework.props = targetframework.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steeltoe.Common", "src\Steeltoe.Common\Steeltoe.Common.csproj", "{4AEA9704-3B99-4317-A959-7D6E4CDD4811}" @@ -41,6 +42,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steeltoe.Common.Security", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steeltoe.Common.Security.Test", "test\Steeltoe.Common.Security.Test\Steeltoe.Common.Security.Test.csproj", "{6E2CBAC4-3FF1-4DC9-9B9B-D0ADFE80218D}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steeltoe.Common.Net.Test", "test\Steeltoe.Common.Net.Test\Steeltoe.Common.Net.Test.csproj", "{1DE7FECF-6A0A-4221-A3C1-165B5DB83506}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -83,6 +86,10 @@ Global {6E2CBAC4-3FF1-4DC9-9B9B-D0ADFE80218D}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E2CBAC4-3FF1-4DC9-9B9B-D0ADFE80218D}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E2CBAC4-3FF1-4DC9-9B9B-D0ADFE80218D}.Release|Any CPU.Build.0 = Release|Any CPU + {1DE7FECF-6A0A-4221-A3C1-165B5DB83506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DE7FECF-6A0A-4221-A3C1-165B5DB83506}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DE7FECF-6A0A-4221-A3C1-165B5DB83506}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DE7FECF-6A0A-4221-A3C1-165B5DB83506}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -97,6 +104,7 @@ Global {5C2D53DB-2980-4393-BCA1-B4C51004E4F7} = {D9798FDE-76F4-4848-8AE0-95249C0101F0} {8D322AD5-ED49-4D40-952C-B38FD97D21EF} = {D9798FDE-76F4-4848-8AE0-95249C0101F0} {6E2CBAC4-3FF1-4DC9-9B9B-D0ADFE80218D} = {CC77ED1F-BC03-4B9D-A07A-186C9A13042B} + {1DE7FECF-6A0A-4221-A3C1-165B5DB83506} = {CC77ED1F-BC03-4B9D-A07A-186C9A13042B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4A85F9DA-2C2D-48E9-A28C-9B35C473C150} diff --git a/src/Steeltoe.Common.Net/Properties/AssemblyInfo.cs b/src/Steeltoe.Common.Net/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ff9335c --- /dev/null +++ b/src/Steeltoe.Common.Net/Properties/AssemblyInfo.cs @@ -0,0 +1,17 @@ +// Copyright 2017 the original author or authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Steeltoe.Common.Net.Test")] diff --git a/src/Steeltoe.Common.Net/Steeltoe.Common.Net.csproj b/src/Steeltoe.Common.Net/Steeltoe.Common.Net.csproj index b97e45e..d9f906f 100644 --- a/src/Steeltoe.Common.Net/Steeltoe.Common.Net.csproj +++ b/src/Steeltoe.Common.Net/Steeltoe.Common.Net.csproj @@ -1,4 +1,4 @@ - + @@ -7,7 +7,7 @@ $(SteeltoeVersion) $(VersionSuffix) Pivotal;dtillman - netstandard2.0 + net461 Steeltoe.Common.Net Steeltoe.Common.Net NET Core;NET Framework diff --git a/src/Steeltoe.Common.Net/WindowsNetworkFileShare.cs b/src/Steeltoe.Common.Net/WindowsNetworkFileShare.cs index bf3c18e..10381c1 100644 --- a/src/Steeltoe.Common.Net/WindowsNetworkFileShare.cs +++ b/src/Steeltoe.Common.Net/WindowsNetworkFileShare.cs @@ -13,15 +13,19 @@ // limitations under the License. using System; +using System.Linq; using System.Net; using System.Runtime.InteropServices; using System.Text; namespace Steeltoe.Common.Net { + /// + /// For interacting with SMB network file shares on Windows + /// public class WindowsNetworkFileShare : IDisposable { - private const int NO_ERROR = 0; + // private const int NO_ERROR = 0; private const int ERROR_ACCESS_DENIED = 5; private const int ERROR_ALREADY_ASSIGNED = 85; private const int ERROR_PATH_NOT_FOUND = 53; @@ -47,7 +51,7 @@ namespace Steeltoe.Common.Net // Created with excel formula: // ="new ErrorClass("&A1&", """&PROPER(SUBSTITUTE(MID(A1,7,LEN(A1)-6), "_", " "))&"""), " - private static ErrorClass[] error_list = new ErrorClass[] + private static readonly ErrorClass[] Error_list = new ErrorClass[] { new ErrorClass(ERROR_ACCESS_DENIED, "Error: Access Denied"), new ErrorClass(ERROR_ALREADY_ASSIGNED, "Error: Already Assigned"), @@ -59,6 +63,7 @@ namespace Steeltoe.Common.Net new ErrorClass(ERROR_INVALID_ADDRESS, "Error: Invalid Address"), new ErrorClass(ERROR_INVALID_PARAMETER, "Error: Invalid Parameter"), new ErrorClass(ERROR_INVALID_PASSWORD, "Error: Invalid Password"), + new ErrorClass(ERROR_INVALID_PASSWORDNAME, "Error: Invalid Password Format"), new ErrorClass(ERROR_MORE_DATA, "Error: More Data"), new ErrorClass(ERROR_NO_MORE_ITEMS, "Error: No More Items"), new ErrorClass(ERROR_NO_NET_OR_BAD_PATH, "Error: No Net Or Bad Path"), @@ -75,8 +80,18 @@ namespace Steeltoe.Common.Net private readonly string _networkName; + /// + /// Initializes a new instance of the class. + /// + /// Address of the file share + /// Username and password for accessing the file share public WindowsNetworkFileShare(string networkName, NetworkCredential credentials) { + if (!Platform.IsWindows) + { + throw new PlatformNotSupportedException("WindowsNetworkFileShare only works on Windows"); + } + _networkName = networkName; var netResource = new NetResource @@ -99,11 +114,17 @@ namespace Steeltoe.Common.Net } } + /// + /// Finalizes an instance of the class. + /// ~WindowsNetworkFileShare() { Dispose(false); } + /// + /// Scope of the file share + /// public enum ResourceScope : int { Connected = 1, @@ -113,6 +134,9 @@ namespace Steeltoe.Common.Net Context } + /// + /// Type of network resource + /// public enum ResourceType : int { Any = 0, @@ -121,6 +145,9 @@ namespace Steeltoe.Common.Net Reserved = 8, } + /// + /// The display options for the network object in a network browsing user interface + /// public enum ResourceDisplaytype : int { Generic = 0x0, @@ -137,6 +164,16 @@ namespace Steeltoe.Common.Net Ndscontainer = 0x0b } + /// + /// Retrieves the most recent extended error code set by a WNet function + /// P/Invoke call to mpr.dll - + /// + /// The error code reported by the network provider. + /// String variable to receive the description of the error + /// Size of error buffer + /// String variable to receive the network provider raising the error + /// Size of name buffer + /// If the function succeeds, and it obtains the last error that the network provider reported, the return value is NO_ERROR.If the caller supplies an invalid buffer, the return value is ERROR_INVALID_ADDRESS. [DllImport("mpr.dll", CharSet = CharSet.Auto)] public static extern int WNetGetLastError( out int error, @@ -145,17 +182,48 @@ namespace Steeltoe.Common.Net out StringBuilder nameBuf, int nameBufSize); + /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } + /// + /// Get a description for an error returned by a P/Invoke call + /// + /// Error code + /// An error message + internal static string GetErrorForNumber(int errNum) + { + if (!Error_list.Any(e => e.Num == errNum)) + { + return "Error: Unknown, " + errNum; + } + else + { + return Error_list.First(e => e.Num == errNum).Message; + } + } + + /// + /// Disposes the object, cancels connection with file share + /// + /// Not used protected virtual void Dispose(bool disposing) { WNetCancelConnection2(_networkName, 0, true); } + /// + /// Makes a connection to a network resource and can redirect a local device to the network resource. + /// P/Invoke call to mpr.dll - + /// + /// Network resource to interact with + /// Password for making the network connection + /// Username for making the network connection + /// A set of connection options - + /// An integer representing the result - [DllImport("mpr.dll")] private static extern int WNetAddConnection2( NetResource netResource, @@ -163,12 +231,36 @@ namespace Steeltoe.Common.Net string username, int flags); + /// + /// Cancels an existing network connection, removes remembered network connections that are not currently connected. + /// P/Invoke call to mpr.dll - + /// + /// + /// Pointer to a constant null-terminated string that specifies the name of either the redirected local device or the remote network resource to disconnect from. + /// If this parameter specifies a redirected local device, the function cancels only the specified device redirection. If the parameter specifies a remote network resource, all connections without devices are canceled. + /// + /// Connection type - + /// Specifies whether the disconnection should occur if there are open files or jobs on the connection. If this parameter is FALSE, the function fails if there are open files or jobs. + /// An integer representing the result - [DllImport("mpr.dll")] private static extern int WNetCancelConnection2( string name, int flags, bool force); + /// + /// Makes a connection to a network resource. Can redirect a local device to a network resource. + /// P/Invoke call to mpr.dll - + /// + /// Handle to a window that the provider of network resources can use as an owner window for dialog boxes + /// Network resource to interact with + /// A null-terminated string that specifies a password to be used in making the network connection + /// A null-terminated string that specifies a user name for making the connection + /// Set of bit flags describing the connection + /// Pointer to a buffer that receives system requests on the connection + /// Pointer to a variable that specifies the size of the lpAccessName buffer, in characters.If the call fails because the buffer is not large enough, the function returns the required buffer size in this location + /// Pointer to a variable that receives additional information about the connection + /// An integer representing the result - [DllImport("mpr.dll")] private static extern int WNetUseConnection( IntPtr hwndOwner, @@ -180,28 +272,6 @@ namespace Steeltoe.Common.Net string lpBufferSize, string lpResult); - private static string GetErrorForNumber(int errNum) - { - foreach (ErrorClass er in error_list) - { - if (er.Num == errNum) - { - return er.Message; - } - } - - return "Error: Unknown, " + errNum; - } - - private static string GetLastError(int result) - { - StringBuilder sbErrorBuf = new StringBuilder(500); - StringBuilder sbNameBuf = new StringBuilder(500); - int resultref = result; - int res = WNetGetLastError(out resultref, out sbErrorBuf, sbErrorBuf.Capacity, out sbNameBuf, sbNameBuf.Capacity); - return sbErrorBuf.ToString(); - } - private struct ErrorClass { public int Num; @@ -209,11 +279,15 @@ namespace Steeltoe.Common.Net public ErrorClass(int num, string message) { - this.Num = num; - this.Message = message; + Num = num; + Message = message; } } + /// + /// The NETRESOURCE structure contains information about a network resource. + /// More info on NetResource: + /// [StructLayout(LayoutKind.Sequential)] public class NetResource { diff --git a/src/Steeltoe.Common/Platform.cs b/src/Steeltoe.Common/Platform.cs index 1059cf6..62c2ec4 100644 --- a/src/Steeltoe.Common/Platform.cs +++ b/src/Steeltoe.Common/Platform.cs @@ -27,6 +27,8 @@ namespace Steeltoe.Common public static bool IsNetCore => RuntimeInformation.FrameworkDescription.StartsWith(NET_CORE); + public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + public static bool IsCloudFoundry => Environment.GetEnvironmentVariable(VCAP_APPLICATION) != null; } } diff --git a/test/Steeltoe.Common.Net.Test/Steeltoe.Common.Net.Test.csproj b/test/Steeltoe.Common.Net.Test/Steeltoe.Common.Net.Test.csproj new file mode 100644 index 0000000..635ca55 --- /dev/null +++ b/test/Steeltoe.Common.Net.Test/Steeltoe.Common.Net.Test.csproj @@ -0,0 +1,37 @@ + + + + + net461 + false + + + SA1101;SA1124;SA1201;SA1309;SA1310;SA1401;SA1600;SA1652;1591 + + + + + + + + PreserveNewest + + + + + + + + + All + + + + + + stylecop.json + Always + + + + diff --git a/test/Steeltoe.Common.Net.Test/WindowsNetworkFileShareTest.cs b/test/Steeltoe.Common.Net.Test/WindowsNetworkFileShareTest.cs new file mode 100644 index 0000000..17430ec --- /dev/null +++ b/test/Steeltoe.Common.Net.Test/WindowsNetworkFileShareTest.cs @@ -0,0 +1,34 @@ +// Copyright 2017 the original author or authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Xunit; + +namespace Steeltoe.Common.Net.Test +{ + public class WindowsNetworkFileShareTest + { + [Fact] + public void GetErrorForKnownNumber_ReturnsKnownError() + { + Assert.Equal("Error: Access Denied", WindowsNetworkFileShare.GetErrorForNumber(5)); + Assert.Equal("Error: No Network", WindowsNetworkFileShare.GetErrorForNumber(1222)); + } + + [Fact] + public void GetErrorForUnknownNumber_ReturnsUnKnownError() + { + Assert.Equal("Error: Unknown, 9999", WindowsNetworkFileShare.GetErrorForNumber(9999)); + } + } +}