Служба просмотра сетевых папок - PullRequest
1 голос
/ 21 марта 2012

в сети есть несколько подобных вопросов, даже несколько здесь, но хотя спрашивающие кажутся счастливыми, я не могу найти тот, который действительно делает то, что мне нужно.

Я пытаюсьдобавьте функцию просмотра удаленного каталога в веб-панель управления администрированием (на основе интрасети).

На данном этапе мне не нужно беспокоиться о безопасности, поскольку это обрабатывается в других местах.

ДляДля этого я использую веб-сервис, который принимает имя сервера и путь к общей папке / папке в качестве параметров.Мне просто нужно, чтобы вернуть подкаталоги этого пути, если они есть.

Звучит не так сложно, не так ли?Что ж, это (по крайней мере для меня!)

Единственный бит, с которым мне нужна помощь, - это на самом деле создание списка каталогов для сервера и предоставленного пути.пожалуйста, не просто ссылку на сайт, как я, наверное, уже видел, но не смог найти рабочее решение;большинство из них даже не пытаются сделать то, что подразумевает название.Некоторое объяснение было бы также полезно!

Приветствия

Ответы [ 4 ]

1 голос
/ 27 марта 2012

Для перечисления подпапок указанной папки в .NET вы можете использовать, например, DirectoryInfo.EnumerateDirectories метод.

Для перечисления общих папок на компьютере вы можете использовать WNetEnumResource встроенная функция, если скрытые административные ресурсы общего доступа, такие как C$, ADMIN$, print$ и т. д., не важны для вас или используйте NetShareEnum для перечисления всех общих ресурсов.

Соответствующий код можетbe

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.Он не содержит реальных сообщений об ошибках.

0 голосов
/ 21 марта 2012

Ну, на самом деле это можно сделать с помощью NetShareEnum Win32API-функции .

Но вот классы-оболочки .NET для перечисления сетевых ресурсов на локальных и удаленных компьютерах и преобразования локального файлапути к UNC путям.Пожалуйста, смотрите статью Сетевые ресурсы и пути UNC .

0 голосов
/ 21 марта 2012

Вы можете использовать метод, описанный здесь , используя 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]\*");

Вы должны добавить "\ *" согласно MSDN

В сетевых ресурсах вы можете использовать lpFileName в форме следующее: "\ Server \ Share *". Однако вы не можете использовать lpFileName это указывает на саму акцию; например, "\ Server \ Share" не действительный.

0 голосов
/ 21 марта 2012

Не уверен, сможем ли мы этого достичь.У нас была похожая проблема, но мы наконец решили ее, указав общий путь (\ SERVERNAME \ FOLDER).

Наиболее важная веб-служба должна использовать учетную запись, которая имеет полное разрешение для доступа к каталогу, иначе исключение, связанное с разрешением, будет выброшено.звонить клиенту.

...