aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.ServerApplication
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2013-10-05 13:13:32 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2013-10-05 13:13:32 -0400
commit478be44dd6deff328cca51306585779bfba7c535 (patch)
tree13ca067291418399c6d4c1993124fad25c89a943 /MediaBrowser.ServerApplication
parent6a665e18072e7ee861d4f964c212980b98712a4d (diff)
create platform-specific network manager implementation
Diffstat (limited to 'MediaBrowser.ServerApplication')
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs6
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj3
-rw-r--r--MediaBrowser.ServerApplication/Networking/NativeMethods.cs72
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs136
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkShares.cs641
5 files changed, 858 insertions, 0 deletions
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 87bd45e507..50074947da 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -48,6 +48,7 @@ using MediaBrowser.Server.Implementations.Session;
using MediaBrowser.Server.Implementations.WebSocket;
using MediaBrowser.ServerApplication.FFMpeg;
using MediaBrowser.ServerApplication.Native;
+using MediaBrowser.ServerApplication.Networking;
using MediaBrowser.WebDashboard.Api;
using System;
using System.Collections.Generic;
@@ -296,6 +297,11 @@ namespace MediaBrowser.ServerApplication
SetKernelProperties();
}
+ protected override INetworkManager CreateNetworkManager()
+ {
+ return new NetworkManager();
+ }
+
/// <summary>
/// Registers the media encoder.
/// </summary>
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index ecd4891a9b..f0ede70b2e 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -198,6 +198,9 @@
<Compile Include="BackgroundServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
+ <Compile Include="Networking\NativeMethods.cs" />
+ <Compile Include="Networking\NetworkManager.cs" />
+ <Compile Include="Networking\NetworkShares.cs" />
<Compile Include="Splash\SplashWindow.xaml.cs">
<DependentUpon>SplashWindow.xaml</DependentUpon>
</Compile>
diff --git a/MediaBrowser.ServerApplication/Networking/NativeMethods.cs b/MediaBrowser.ServerApplication/Networking/NativeMethods.cs
new file mode 100644
index 0000000000..20f7ac23d8
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Networking/NativeMethods.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace MediaBrowser.ServerApplication.Networking
+{
+ /// <summary>
+ /// Class NativeMethods
+ /// </summary>
+ [SuppressUnmanagedCodeSecurity]
+ public static class NativeMethods
+ {
+ //declare the Netapi32 : NetServerEnum method import
+ /// <summary>
+ /// Nets the server enum.
+ /// </summary>
+ /// <param name="ServerName">Name of the server.</param>
+ /// <param name="dwLevel">The dw level.</param>
+ /// <param name="pBuf">The p buf.</param>
+ /// <param name="dwPrefMaxLen">The dw pref max len.</param>
+ /// <param name="dwEntriesRead">The dw entries read.</param>
+ /// <param name="dwTotalEntries">The dw total entries.</param>
+ /// <param name="dwServerType">Type of the dw server.</param>
+ /// <param name="domain">The domain.</param>
+ /// <param name="dwResumeHandle">The dw resume handle.</param>
+ /// <returns>System.Int32.</returns>
+ [DllImport("Netapi32", CharSet = CharSet.Auto, SetLastError = true),
+ SuppressUnmanagedCodeSecurity]
+
+ public static extern int NetServerEnum(
+ string ServerName, // must be null
+ int dwLevel,
+ ref IntPtr pBuf,
+ int dwPrefMaxLen,
+ out int dwEntriesRead,
+ out int dwTotalEntries,
+ int dwServerType,
+ string domain, // null for login domain
+ out int dwResumeHandle
+ );
+
+ //declare the Netapi32 : NetApiBufferFree method import
+ /// <summary>
+ /// Nets the API buffer free.
+ /// </summary>
+ /// <param name="pBuf">The p buf.</param>
+ /// <returns>System.Int32.</returns>
+ [DllImport("Netapi32", SetLastError = true),
+ SuppressUnmanagedCodeSecurity]
+
+ public static extern int NetApiBufferFree(
+ IntPtr pBuf);
+ }
+
+ //create a _SERVER_INFO_100 STRUCTURE
+ /// <summary>
+ /// Struct _SERVER_INFO_100
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential)]
+ public struct _SERVER_INFO_100
+ {
+ /// <summary>
+ /// The sv100_platform_id
+ /// </summary>
+ internal int sv100_platform_id;
+ /// <summary>
+ /// The sv100_name
+ /// </summary>
+ [MarshalAs(UnmanagedType.LPWStr)]
+ internal string sv100_name;
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
new file mode 100644
index 0000000000..4799dcc723
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -0,0 +1,136 @@
+using MediaBrowser.Common.Implementations.Networking;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Net;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.ServerApplication.Networking
+{
+ /// <summary>
+ /// Class NetUtils
+ /// </summary>
+ public class NetworkManager : BaseNetworkManager, INetworkManager
+ {
+ /// <summary>
+ /// Gets the network shares.
+ /// </summary>
+ /// <param name="path">The path.</param>
+ /// <returns>IEnumerable{NetworkShare}.</returns>
+ public IEnumerable<NetworkShare> GetNetworkShares(string path)
+ {
+ return new ShareCollection(path).OfType<Share>().Select(ToNetworkShare);
+ }
+
+ /// <summary>
+ /// To the network share.
+ /// </summary>
+ /// <param name="share">The share.</param>
+ /// <returns>NetworkShare.</returns>
+ private NetworkShare ToNetworkShare(Share share)
+ {
+ return new NetworkShare
+ {
+ Name = share.NetName,
+ Path = share.Path,
+ Remark = share.Remark,
+ Server = share.Server,
+ ShareType = ToNetworkShareType(share.ShareType)
+ };
+ }
+
+ /// <summary>
+ /// To the type of the network share.
+ /// </summary>
+ /// <param name="shareType">Type of the share.</param>
+ /// <returns>NetworkShareType.</returns>
+ /// <exception cref="System.ArgumentException">Unknown share type</exception>
+ private NetworkShareType ToNetworkShareType(ShareType shareType)
+ {
+ if (shareType.HasFlag(ShareType.Special))
+ {
+ return NetworkShareType.Special;
+ }
+ if (shareType.HasFlag(ShareType.Device))
+ {
+ return NetworkShareType.Device;
+ }
+ if (shareType.HasFlag(ShareType.Disk))
+ {
+ return NetworkShareType.Disk;
+ }
+ if (shareType.HasFlag(ShareType.IPC))
+ {
+ return NetworkShareType.Ipc;
+ }
+ if (shareType.HasFlag(ShareType.Printer))
+ {
+ return NetworkShareType.Printer;
+ }
+ throw new ArgumentException("Unknown share type");
+ }
+
+ /// <summary>
+ /// Uses the DllImport : NetServerEnum with all its required parameters
+ /// (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
+ /// for full details or method signature) to retrieve a list of domain SV_TYPE_WORKSTATION
+ /// and SV_TYPE_SERVER PC's
+ /// </summary>
+ /// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER
+ /// PC's in the Domain</returns>
+ public IEnumerable<string> GetNetworkDevices()
+ {
+ //local fields
+ const int MAX_PREFERRED_LENGTH = -1;
+ var SV_TYPE_WORKSTATION = 1;
+ var SV_TYPE_SERVER = 2;
+ var buffer = IntPtr.Zero;
+ var tmpBuffer = IntPtr.Zero;
+ var entriesRead = 0;
+ var totalEntries = 0;
+ var resHandle = 0;
+ var sizeofINFO = Marshal.SizeOf(typeof(_SERVER_INFO_100));
+
+ try
+ {
+ //call the DllImport : NetServerEnum with all its required parameters
+ //see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp
+ //for full details of method signature
+ var ret = NativeMethods.NetServerEnum(null, 100, ref buffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, SV_TYPE_WORKSTATION | SV_TYPE_SERVER, null, out resHandle);
+
+ //if the returned with a NERR_Success (C++ term), =0 for C#
+ if (ret == 0)
+ {
+ //loop through all SV_TYPE_WORKSTATION and SV_TYPE_SERVER PC's
+ for (var i = 0; i < totalEntries; i++)
+ {
+ //get pointer to, Pointer to the buffer that received the data from
+ //the call to NetServerEnum. Must ensure to use correct size of
+ //STRUCTURE to ensure correct location in memory is pointed to
+ tmpBuffer = new IntPtr((int)buffer + (i * sizeofINFO));
+ //Have now got a pointer to the list of SV_TYPE_WORKSTATION and
+ //SV_TYPE_SERVER PC's, which is unmanaged memory
+ //Needs to Marshal data from an unmanaged block of memory to a
+ //managed object, again using STRUCTURE to ensure the correct data
+ //is marshalled
+ var svrInfo = (_SERVER_INFO_100)Marshal.PtrToStructure(tmpBuffer, typeof(_SERVER_INFO_100));
+
+ //add the PC names to the ArrayList
+ if (!string.IsNullOrEmpty(svrInfo.sv100_name))
+ {
+ yield return svrInfo.sv100_name;
+ }
+ }
+ }
+ }
+ finally
+ {
+ //The NetApiBufferFree function frees
+ //the memory that the NetApiBufferAllocate function allocates
+ NativeMethods.NetApiBufferFree(buffer);
+ }
+ }
+ }
+
+}
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkShares.cs b/MediaBrowser.ServerApplication/Networking/NetworkShares.cs
new file mode 100644
index 0000000000..91bd167b83
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Networking/NetworkShares.cs
@@ -0,0 +1,641 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.ServerApplication.Networking
+{
+ /// <summary>
+ /// Type of share
+ /// </summary>
+ [Flags]
+ public enum ShareType
+ {
+ /// <summary>Disk share</summary>
+ Disk = 0,
+ /// <summary>Printer share</summary>
+ Printer = 1,
+ /// <summary>Device share</summary>
+ Device = 2,
+ /// <summary>IPC share</summary>
+ IPC = 3,
+ /// <summary>Special share</summary>
+ Special = -2147483648, // 0x80000000,
+ }
+
+ #region Share
+
+ /// <summary>
+ /// Information about a local share
+ /// </summary>
+ public class Share
+ {
+ #region Private data
+
+ private string _server;
+ private string _netName;
+ private string _path;
+ private ShareType _shareType;
+ private string _remark;
+
+ #endregion
+
+ #region Constructor
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="server">The server.</param>
+ /// <param name="netName">Name of the net.</param>
+ /// <param name="path">The path.</param>
+ /// <param name="shareType">Type of the share.</param>
+ /// <param name="remark">The remark.</param>
+ public Share(string server, string netName, string path, ShareType shareType, string remark)
+ {
+ if (ShareType.Special == shareType && "IPC$" == netName)
+ {
+ shareType |= ShareType.IPC;
+ }
+
+ _server = server;
+ _netName = netName;
+ _path = path;
+ _shareType = shareType;
+ _remark = remark;
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the computer that this share belongs to
+ /// </summary>
+ public string Server
+ {
+ get { return _server; }
+ }
+
+ /// <summary>
+ /// Share name
+ /// </summary>
+ public string NetName
+ {
+ get { return _netName; }
+ }
+
+ /// <summary>
+ /// Local path
+ /// </summary>
+ public string Path
+ {
+ get { return _path; }
+ }
+
+ /// <summary>
+ /// Share type
+ /// </summary>
+ public ShareType ShareType
+ {
+ get { return _shareType; }
+ }
+
+ /// <summary>
+ /// Comment
+ /// </summary>
+ public string Remark
+ {
+ get { return _remark; }
+ }
+
+ /// <summary>
+ /// Returns true if this is a file system share
+ /// </summary>
+ public bool IsFileSystem
+ {
+ get
+ {
+ // Shared device
+ if (0 != (_shareType & ShareType.Device)) return false;
+ // IPC share
+ if (0 != (_shareType & ShareType.IPC)) return false;
+ // Shared printer
+ if (0 != (_shareType & ShareType.Printer)) return false;
+
+ // Standard disk share
+ if (0 == (_shareType & ShareType.Special)) return true;
+
+ // Special disk share (e.g. C$)
+ return ShareType.Special == _shareType && !string.IsNullOrEmpty(_netName);
+ }
+ }
+
+ /// <summary>
+ /// Get the root of a disk-based share
+ /// </summary>
+ public DirectoryInfo Root
+ {
+ get
+ {
+ if (IsFileSystem)
+ {
+ if (string.IsNullOrEmpty(_server))
+ if (string.IsNullOrEmpty(_path))
+ return new DirectoryInfo(ToString());
+ else
+ return new DirectoryInfo(_path);
+ return new DirectoryInfo(ToString());
+ }
+ return null;
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Returns the path to this share
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ if (string.IsNullOrEmpty(_server))
+ {
+ return string.Format(@"\\{0}\{1}", Environment.MachineName, _netName);
+ }
+ return string.Format(@"\\{0}\{1}", _server, _netName);
+ }
+
+ /// <summary>
+ /// Returns true if this share matches the local path
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ public bool MatchesPath(string path)
+ {
+ if (!IsFileSystem) return false;
+ if (string.IsNullOrEmpty(path)) return true;
+
+ return path.ToLower().StartsWith(_path.ToLower());
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// A collection of shares
+ /// </summary>
+ public class ShareCollection : ReadOnlyCollectionBase
+ {
+ #region Platform
+
+ /// <summary>
+ /// Is this an NT platform?
+ /// </summary>
+ protected static bool IsNT
+ {
+ get { return (PlatformID.Win32NT == Environment.OSVersion.Platform); }
+ }
+
+ /// <summary>
+ /// Returns true if this is Windows 2000 or higher
+ /// </summary>
+ protected static bool IsW2KUp
+ {
+ get
+ {
+ OperatingSystem os = Environment.OSVersion;
+ if (PlatformID.Win32NT == os.Platform && os.Version.Major >= 5)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Interop
+
+ #region Constants
+
+ /// <summary>Maximum path length</summary>
+ protected const int MAX_PATH = 260;
+ /// <summary>No error</summary>
+ protected const int NO_ERROR = 0;
+ /// <summary>Access denied</summary>
+ protected const int ERROR_ACCESS_DENIED = 5;
+ /// <summary>Access denied</summary>
+ protected const int ERROR_WRONG_LEVEL = 124;
+ /// <summary>More data available</summary>
+ protected const int ERROR_MORE_DATA = 234;
+ /// <summary>Not connected</summary>
+ protected const int ERROR_NOT_CONNECTED = 2250;
+ /// <summary>Level 1</summary>
+ protected const int UNIVERSAL_NAME_INFO_LEVEL = 1;
+ /// <summary>Max extries (9x)</summary>
+ protected const int MAX_SI50_ENTRIES = 20;
+
+ #endregion
+
+ #region Structures
+
+ /// <summary>Unc name</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ protected struct UNIVERSAL_NAME_INFO
+ {
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string lpUniversalName;
+ }
+
+ /// <summary>Share information, NT, level 2</summary>
+ /// <remarks>
+ /// Requires admin rights to work.
+ /// </remarks>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ protected struct SHARE_INFO_2
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string NetName;
+ public ShareType ShareType;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Remark;
+ public int Permissions;
+ public int MaxUsers;
+ public int CurrentUsers;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Path;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Password;
+ }
+
+ /// <summary>Share information, NT, level 1</summary>
+ /// <remarks>
+ /// Fallback when no admin rights.
+ /// </remarks>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ protected struct SHARE_INFO_1
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string NetName;
+ public ShareType ShareType;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Remark;
+ }
+
+ /// <summary>Share information, Win9x</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
+ protected struct SHARE_INFO_50
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
+ public string NetName;
+
+ public byte bShareType;
+ public ushort Flags;
+
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Remark;
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Path;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
+ public string PasswordRW;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]
+ public string PasswordRO;
+
+ public ShareType ShareType
+ {
+ get { return (ShareType)((int)bShareType & 0x7F); }
+ }
+ }
+
+ /// <summary>Share information level 1, Win9x</summary>
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
+ protected struct SHARE_INFO_1_9x
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)]
+ public string NetName;
+ public byte Padding;
+
+ public ushort bShareType;
+
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string Remark;
+
+ public ShareType ShareType
+ {
+ get { return (ShareType)((int)bShareType & 0x7FFF); }
+ }
+ }
+
+ #endregion
+
+ #region Functions
+
+ /// <summary>Get a UNC name</summary>
+ [DllImport("mpr", CharSet = CharSet.Auto)]
+ protected static extern int WNetGetUniversalName(string lpLocalPath,
+ int dwInfoLevel, ref UNIVERSAL_NAME_INFO lpBuffer, ref int lpBufferSize);
+
+ /// <summary>Get a UNC name</summary>
+ [DllImport("mpr", CharSet = CharSet.Auto)]
+ protected static extern int WNetGetUniversalName(string lpLocalPath,
+ int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize);
+
+ /// <summary>Enumerate shares (NT)</summary>
+ [DllImport("netapi32", CharSet = CharSet.Unicode)]
+ protected static extern int NetShareEnum(string lpServerName, int dwLevel,
+ out IntPtr lpBuffer, int dwPrefMaxLen, out int entriesRead,
+ out int totalEntries, ref int hResume);
+
+ /// <summary>Enumerate shares (9x)</summary>
+ [DllImport("svrapi", CharSet = CharSet.Ansi)]
+ protected static extern int NetShareEnum(
+ [MarshalAs(UnmanagedType.LPTStr)] string lpServerName, int dwLevel,
+ IntPtr lpBuffer, ushort cbBuffer, out ushort entriesRead,
+ out ushort totalEntries);
+
+ /// <summary>Free the buffer (NT)</summary>
+ [DllImport("netapi32")]
+ protected static extern int NetApiBufferFree(IntPtr lpBuffer);
+
+ #endregion
+
+ #region Enumerate shares
+
+ /// <summary>
+ /// Enumerates the shares on Windows NT
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateSharesNT(string server, ShareCollection shares)
+ {
+ int level = 2;
+ int entriesRead, totalEntries, nRet, hResume = 0;
+ IntPtr pBuffer = IntPtr.Zero;
+
+ try
+ {
+ nRet = NetShareEnum(server, level, out pBuffer, -1,
+ out entriesRead, out totalEntries, ref hResume);
+
+ if (ERROR_ACCESS_DENIED == nRet)
+ {
+ //Need admin for level 2, drop to level 1
+ level = 1;
+ nRet = NetShareEnum(server, level, out pBuffer, -1,
+ out entriesRead, out totalEntries, ref hResume);
+ }
+
+ if (NO_ERROR == nRet && entriesRead > 0)
+ {
+ Type t = (2 == level) ? typeof(SHARE_INFO_2) : typeof(SHARE_INFO_1);
+ int offset = Marshal.SizeOf(t);
+
+ for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += offset)
+ {
+ IntPtr pItem = new IntPtr(lpItem);
+ if (1 == level)
+ {
+ SHARE_INFO_1 si = (SHARE_INFO_1)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
+ }
+ else
+ {
+ SHARE_INFO_2 si = (SHARE_INFO_2)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
+ }
+ }
+ }
+
+ }
+ finally
+ {
+ // Clean up buffer allocated by system
+ if (IntPtr.Zero != pBuffer)
+ NetApiBufferFree(pBuffer);
+ }
+ }
+
+ /// <summary>
+ /// Enumerates the shares on Windows 9x
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateShares9x(string server, ShareCollection shares)
+ {
+ int level = 50;
+ int nRet = 0;
+ ushort entriesRead, totalEntries;
+
+ var t = typeof(SHARE_INFO_50);
+ var size = Marshal.SizeOf(t);
+ var cbBuffer = (ushort)(MAX_SI50_ENTRIES * size);
+ //On Win9x, must allocate buffer before calling API
+ IntPtr pBuffer = Marshal.AllocHGlobal(cbBuffer);
+
+ try
+ {
+ nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
+ out entriesRead, out totalEntries);
+
+ if (ERROR_WRONG_LEVEL == nRet)
+ {
+ level = 1;
+ t = typeof(SHARE_INFO_1_9x);
+ size = Marshal.SizeOf(t);
+
+ nRet = NetShareEnum(server, level, pBuffer, cbBuffer,
+ out entriesRead, out totalEntries);
+ }
+
+ if (NO_ERROR == nRet || ERROR_MORE_DATA == nRet)
+ {
+ for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += size)
+ {
+ var pItem = new IntPtr(lpItem);
+
+ if (1 == level)
+ {
+ var si = (SHARE_INFO_1_9x)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark);
+ }
+ else
+ {
+ var si = (SHARE_INFO_50)Marshal.PtrToStructure(pItem, t);
+ shares.Add(si.NetName, si.Path, si.ShareType, si.Remark);
+ }
+ }
+ }
+ else
+ Console.WriteLine(nRet);
+
+ }
+ finally
+ {
+ //Clean up buffer
+ Marshal.FreeHGlobal(pBuffer);
+ }
+ }
+
+ /// <summary>
+ /// Enumerates the shares
+ /// </summary>
+ /// <param name="server">The server name</param>
+ /// <param name="shares">The ShareCollection</param>
+ protected static void EnumerateShares(string server, ShareCollection shares)
+ {
+ if (null != server && 0 != server.Length && !IsW2KUp)
+ {
+ server = server.ToUpper();
+
+ // On NT4, 9x and Me, server has to start with "\\"
+ if (!('\\' == server[0] && '\\' == server[1]))
+ server = @"\\" + server;
+ }
+
+ if (IsNT)
+ EnumerateSharesNT(server, shares);
+ else
+ EnumerateShares9x(server, shares);
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Static methods
+
+ /// <summary>
+ /// Returns true if fileName is a valid local file-name of the form:
+ /// X:\, where X is a drive letter from A-Z
+ /// </summary>
+ /// <param name="fileName">The filename to check</param>
+ /// <returns></returns>
+ public static bool IsValidFilePath(string fileName)
+ {
+ if (null == fileName || 0 == fileName.Length) return false;
+
+ char drive = char.ToUpper(fileName[0]);
+ if ('A' > drive || drive > 'Z')
+ return false;
+
+ else if (Path.VolumeSeparatorChar != fileName[1])
+ return false;
+ else if (Path.DirectorySeparatorChar != fileName[2])
+ return false;
+ else
+ return true;
+ }
+
+ #endregion
+
+ /// <summary>The name of the server this collection represents</summary>
+ private string _server;
+
+ #region Constructor
+
+ /// <summary>
+ /// Default constructor - local machine
+ /// </summary>
+ public ShareCollection()
+ {
+ _server = string.Empty;
+ EnumerateShares(_server, this);
+ }
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="server">The server.</param>
+ public ShareCollection(string server)
+ {
+ _server = server;
+ EnumerateShares(_server, this);
+ }
+
+ #endregion
+
+ #region Add
+
+ protected void Add(Share share)
+ {
+ InnerList.Add(share);
+ }
+
+ protected void Add(string netName, string path, ShareType shareType, string remark)
+ {
+ InnerList.Add(new Share(_server, netName, path, shareType, remark));
+ }
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Returns the name of the server this collection represents
+ /// </summary>
+ public string Server
+ {
+ get { return _server; }
+ }
+
+ /// <summary>
+ /// Returns the <see cref="Share"/> at the specified index.
+ /// </summary>
+ public Share this[int index]
+ {
+ get { return (Share)InnerList[index]; }
+ }
+
+ /// <summary>
+ /// Returns the <see cref="Share"/> which matches a given local path
+ /// </summary>
+ /// <param name="path">The path to match</param>
+ public Share this[string path]
+ {
+ get
+ {
+ if (null == path || 0 == path.Length) return null;
+
+ path = Path.GetFullPath(path);
+ if (!IsValidFilePath(path)) return null;
+
+ Share match = null;
+
+ foreach (object t in InnerList)
+ {
+ var s = (Share)t;
+
+ if (s.IsFileSystem && s.MatchesPath(path))
+ {
+ //Store first match
+ if (null == match)
+ match = s;
+
+ // If this has a longer path,
+ // and this is a disk share or match is a special share,
+ // then this is a better match
+ else if (match.Path.Length < s.Path.Length)
+ {
+ if (ShareType.Disk == s.ShareType || ShareType.Disk != match.ShareType)
+ match = s;
+ }
+ }
+ }
+
+ return match;
+ }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Copy this collection to an array
+ /// </summary>
+ /// <param name="array"></param>
+ /// <param name="index"></param>
+ public void CopyTo(Share[] array, int index)
+ {
+ InnerList.CopyTo(array, index);
+ }
+ }
+} \ No newline at end of file