网络文件夹浏览器服务

时间:2012-03-21 16:56:11

标签: c# web-services browser filesystems directory

网上有一些类似的问题 - 即使是在这里也有一些问题,但即使这些问题似乎很高兴,我也找不到真正能满足我需要的东西。

我正在尝试将远程目录浏览功能添加到基于Web的管理控制面板(基于Intranet)。

此时我不需要担心安全性,因为这是在其他地方处理的。

要做到这一点,我正在使用一个web服务,它接受服务器名称和共享/文件夹路径作为参数。我只需要它返回此路径的子目录,如果有的话。

听起来不是那么难,是吗?嗯,这是(至少对我来说!)

我唯一需要帮助的是实际生成服务器和路径的目录列表。

所有的帮助都表示赞赏,但请不要只是链接到一个网站,因为我可能已经看到它,但未能得到一个有效的解决方案;其中大多数甚至似乎都没有尝试做标题所暗示的。 一些解释也会有所帮助!

干杯

4 个答案:

答案 0 :(得分:1)

要枚举.NET中指定文件夹的子文件夹,您可以使用例如DirectoryInfo.EnumerateDirectories方法。

要枚举某些计算机的共享,如果C$ADMIN$print$等隐藏的管理共享对您不重要,则可以使用WNetEnumResource本机功能使用NetShareEnum枚举所有共享。

相应的代码可能是

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;

namespace Subfolders {
    static internal class Native {
        [DllImport ("Netapi32.dll", SetLastError = true)]
        internal static extern uint NetApiBufferFree (IntPtr buffer);

        [DllImport ("Netapi32.dll", CharSet = CharSet.Unicode)]
        internal static extern uint NetShareEnum (
             string serverName,
             int level,
             ref IntPtr bufPtr,
             uint prefmaxlen,
             ref int entriesread,
             ref int totalentries,
             ref int resumeHandle
        );

        [DllImport ("MPR.dll", CharSet = CharSet.Auto)]
        internal static extern uint WNetEnumResource(IntPtr hEnum, ref int lpcCount, IntPtr lpBuffer, ref int lpBufferSize);

        [DllImport ("MPR.dll", CharSet = CharSet.Auto)]
        internal static extern uint WNetOpenEnum(ResourceScope dwScope, ResourceType dwType, ResourceUsage dwUsage,
            IntPtr lpNetResource, out IntPtr lphEnum);

        [DllImport ("MPR.dll", CharSet = CharSet.Auto)]
        internal static extern uint WNetCloseEnum(IntPtr hEnum);

        internal const uint MaxPreferredLength = 0xFFFFFFFF;
        internal const int NerrSuccess = 0;
        internal enum NetError : uint {
            NerrSuccess = 0,
            NerrBase = 2100,
            NerrUnknownDevDir = (NerrBase + 16),
            NerrDuplicateShare = (NerrBase + 18),
            NerrBufTooSmall = (NerrBase + 23),
        }
        internal enum ShareType : uint {
            StypeDisktree = 0,
            StypePrintq = 1,
            StypeDevice = 2,
            StypeIpc = 3,
            StypeSpecial = 0x80000000,
        }
        [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct ShareInfo1 {
            public string shi1_netname;
            public uint shi1_type;
            public string shi1_remark;
            public ShareInfo1 (string sharename, uint sharetype, string remark) {
                shi1_netname = sharename;
                shi1_type = sharetype;
                shi1_remark = remark;
            }
            public override string ToString () {
                return shi1_netname;
            }
        }
        public enum ResourceScope: uint {
            ResourceConnected = 0x00000001,
            ResourceGlobalnet = 0x00000002,
            ResourceRemembered = 0x00000003,
            ResourceRecent = 0x00000004,
            ResourceContext = 0x00000005
        }
        public enum ResourceType: uint {
            ResourcetypeAny = 0x00000000,
            ResourcetypeDisk = 0x00000001,
            ResourcetypePrint = 0x00000002,
            ResourcetypeReserved = 0x00000008,
            ResourcetypeUnknown = 0xFFFFFFFF
        }
        public enum ResourceUsage: uint {
            ResourceusageConnectable = 0x00000001,
            ResourceusageContainer = 0x00000002,
            ResourceusageNolocaldevice = 0x00000004,
            ResourceusageSibling = 0x00000008,
            ResourceusageAttached = 0x00000010,
            ResourceusageAll = (ResourceusageConnectable | ResourceusageContainer | ResourceusageAttached),
            ResourceusageReserved = 0x80000000
        }
        public enum ResourceDisplaytype: uint {
            ResourcedisplaytypeGeneric = 0x00000000,
            ResourcedisplaytypeDomain = 0x00000001,
            ResourcedisplaytypeServer = 0x00000002,
            ResourcedisplaytypeShare = 0x00000003,
            ResourcedisplaytypeFile = 0x00000004,
            ResourcedisplaytypeGroup = 0x00000005,
            ResourcedisplaytypeNetwork = 0x00000006,
            ResourcedisplaytypeRoot = 0x00000007,
            ResourcedisplaytypeShareadmin = 0x00000008,
            ResourcedisplaytypeDirectory = 0x00000009,
            ResourcedisplaytypeTree = 0x0000000A,
            ResourcedisplaytypeNdscontainer = 0x0000000B
        }
        [StructLayout (LayoutKind.Sequential)]
        public struct NetResource {
            public ResourceScope dwScope;
            public ResourceType dwType;
            public ResourceDisplaytype dwDisplayType;
            public ResourceUsage dwUsage;
            [MarshalAs (UnmanagedType.LPTStr)]
            public string lpLocalName;
            [MarshalAs (UnmanagedType.LPTStr)]
            public string lpRemoteName;
            [MarshalAs (UnmanagedType.LPTStr)]
            public string lpComment;
            [MarshalAs (UnmanagedType.LPTStr)]
            public string lpProvider;
        }
    }
    class Program {
        static IEnumerable<string> GetShares(string computerName) {
            var resources = new List<string>();
            IntPtr hEnum = IntPtr.Zero, pResource = IntPtr.Zero;
            try {
                var resource = new Native.NetResource();
                int bufferSize = 163840;
                resource.dwType = Native.ResourceType.ResourcetypeAny;
                resource.dwScope = Native.ResourceScope.ResourceGlobalnet;
                resource.dwUsage = Native.ResourceUsage.ResourceusageContainer;
                resource.lpRemoteName = computerName;
                pResource = Marshal.AllocHGlobal(Marshal.SizeOf(resource));
                Marshal.StructureToPtr (resource, pResource, false);
                uint status = Native.WNetOpenEnum (Native.ResourceScope.ResourceGlobalnet,
                                                   Native.ResourceType.ResourcetypeDisk,
                                                   0,
                                                   pResource,
                                                   out hEnum);
                if (status != 0)
                    return resources;

                int numberOfEntries = -1;
                IntPtr pBuffer = Marshal.AllocHGlobal(bufferSize);
                status = Native.WNetEnumResource (hEnum, ref numberOfEntries, pBuffer, ref bufferSize);
                if (status == Native.NerrSuccess && numberOfEntries > 0) {
                    var ptr = pBuffer;
                    for (int i = 0; i < numberOfEntries; i++, ptr += Marshal.SizeOf(resource)) {
                        resource = (Native.NetResource)Marshal.PtrToStructure (ptr, typeof (Native.NetResource));
                        resources.Add (resource.lpRemoteName.StartsWith (computerName + '\\',
                                                                         StringComparison.OrdinalIgnoreCase)
                                           ? resource.lpRemoteName.Substring (computerName.Length + 1)
                                           : resource.lpRemoteName);
                    }
                }
            } finally {
                if (hEnum != IntPtr.Zero) {
                    Native.WNetCloseEnum (hEnum);
                }
                if (pResource != IntPtr.Zero) {
                    Marshal.FreeHGlobal(pResource);
                }
            }
            return resources;
        }

        static IEnumerable<string> GetAllShares (string computerName) {
            var shares = new List<string> ();
            IntPtr bufPtr = IntPtr.Zero;
            int entriesread = 0;
            int totalentries = 0;
            int resumeHandle = 0;
            int nStructSize = Marshal.SizeOf (typeof (Native.ShareInfo1));
            try {
                uint ret = Native.NetShareEnum (computerName, 1, ref bufPtr,
                    Native.MaxPreferredLength,
                    ref entriesread,
                    ref totalentries,
                    ref resumeHandle);
                if (ret == (uint)Native.NetError.NerrSuccess) {
                    var currentPtr = bufPtr;
                    for (int i = 0; i < entriesread; i++) {
                        var shi1 = (Native.ShareInfo1)Marshal.PtrToStructure (currentPtr, typeof (Native.ShareInfo1));
                        if ((shi1.shi1_type & ~(uint)Native.ShareType.StypeSpecial) == (uint)Native.ShareType.StypeDisktree) {
                            shares.Add (shi1.shi1_netname);
                        }
                        currentPtr = new IntPtr (currentPtr.ToInt32 () + nStructSize);
                    }
                }
            } finally {
                if (bufPtr != IntPtr.Zero)
                    Native.NetApiBufferFree (bufPtr);
            }
            return shares;
        }
        static IEnumerable<string> GetSubdirectories (string root) {
            var dirInfo = new DirectoryInfo (root);
            return (from info in dirInfo.EnumerateDirectories () select info.Name).ToList();
        }
        static void Main () {
            var root = @"\\OK01\Users";
            Console.WriteLine ("Subdirectories of {0}:", root);
            foreach (var dir in GetSubdirectories (root)) {
                Console.WriteLine (dir);
            }

            Console.WriteLine ();
            root = @"\\OK01\Users\Public";
            Console.WriteLine ("Subdirectories of {0}:", root);
            foreach (var dir in GetSubdirectories (root)) {
                Console.WriteLine (dir);
            }

            Console.WriteLine ();
            root = @"\\OK01";
            Console.WriteLine ("All Shares of {0} (inclusive hidden):", root);
            foreach (var shareName in GetAllShares (root)) {
                Console.WriteLine (shareName);
            }

            Console.WriteLine ();
            root = @"\\OK01";
            Console.WriteLine ("Shares of {0}:", root);
            foreach (var shareName in GetShares (root)) {
                Console.WriteLine (shareName);
            }
        }
    }
}

产生类似

的输出
Subdirectories of \\OK01\Users:
All Users
ASP.NET v4.0
Default
Default User
MSSQL$SQL2012
Oleg
Public

Subdirectories of \\OK01\Users\Public:
Desktop
Documents
Downloads
Favorites
Libraries
Music
Pictures
Recorded TV
Roaming
Videos

All Shares of \\OK01 (inclusive hidden):
ADMIN$
C$
print$
Q$
Users
Virtual Machines
VMware

Shares of \\OK01:
Users
Virtual Machines
VMware

上面的代码经过简化,仅演示了如何使用相应的API。它不包含真正的错误报告。

答案 1 :(得分:0)

不确定我们能否实现这一目标。我们有类似的问题,但最终通过提供共享路径(\ SERVERNAME \ FOLDER)来解决它。

最重要的Web服务应该使用具有访问目录的完全权限的帐户,否则与权限相关的异常将被抛出到调用客户端。

答案 2 :(得分:0)

嗯,实际上可以使用NetShareEnum Win32API function完成。

但是这里是.NET包装类,用于枚举本地和远程计算机上的网络共享,并将本地文件路径转换为UNC路径。请参阅文章Network Shares and UNC paths

答案 3 :(得分:0)

您可以使用here using Interop描述的方法。

我对代码进行了一些修改以提出这个问题。 我没有对此进行过广泛测试,因此可能会有错误,但它应该让您入门。

private List<string> GetSubDirectories(string serverName, string folderPath)
{
        List<string> subDirectories = new List<string>();
        string folder_path = Path.Combine(serverName, folderPath);            
        IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

        WIN32_FIND_DATA findData;

        IntPtr findHandle;

        findHandle = FindFirstFile(folder_path, out findData);
        if (findHandle == INVALID_HANDLE_VALUE)
        {
            int error = Marshal.GetLastWin32Error();
            Console.WriteLine(error.ToString());
            return null;
        }

        do
        {
            try
            {
                if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
                    subDirectories.Add(findData.cFileName);                    
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        while (FindNextFile(findHandle, out findData));
        FindClose(findHandle);

        return subDirectories;
    }

    public const int FILE_ATTRIBUTE_DIRECTORY = 0x10;

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool FindClose(IntPtr hFindFile);

    [StructLayout(LayoutKind.Sequential)]
    public struct FILETIME
    {
        public uint dwLowDateTime;
        public uint dwHighDateTime;
    };

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct WIN32_FIND_DATA
    {
        public uint dwFileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public uint dwReserved0;
        public uint dwReserved1;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
        public string cAlternateFileName;
    }


    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public static extern bool CloseHandle(IntPtr handle);

}

你可以这样称呼:

var subdirectories = GetSubDirectories(@"\\[serverName]", @"[folderPath]\*");

您必须添加“\ *”as per MSDN

  

在网络共享上,您可以使用lpFileName的形式   以下:“\ Server \ Share *”。但是,您不能使用lpFileName   这指向了共享本身;例如,“\ Server \ Share”不是   有效的。