Windows文件管理器开发:程序化访问LAN共享文件与设备
解决方案
一、枚举局域网内的网络设备/机器名
使用Windows原生API WNetEnumResource 实现网络资源枚举,比PowerShell命令更稳定可靠,以下是C#示例代码:
using System; using System.Collections.Generic; using System.Runtime.InteropServices; public class NetworkBrowser { [DllImport("mpr.dll")] private static extern int WNetOpenEnum(int dwScope, int dwType, int dwUsage, IntPtr lpNetResource, out IntPtr lphEnum); [DllImport("mpr.dll")] private static extern int WNetEnumResource(IntPtr hEnum, ref int lpcCount, IntPtr lpBuffer, ref int lpBufferSize); [DllImport("mpr.dll")] private static extern int WNetCloseEnum(IntPtr hEnum); private const int RESOURCE_GLOBALNET = 0x00000002; private const int RESOURCETYPE_DISK = 0x00000001; private const int RESOURCEUSAGE_CONTAINER = 0x00000002; public static List<string> GetNetworkComputers() { List<string> computers = new List<string>(); IntPtr hEnum = IntPtr.Zero; try { int result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, RESOURCEUSAGE_CONTAINER, IntPtr.Zero, out hEnum); if (result != 0) return computers; int bufferSize = 16384; IntPtr buffer = Marshal.AllocHGlobal(bufferSize); try { int entriesRead; do { entriesRead = 0; result = WNetEnumResource(hEnum, ref entriesRead, buffer, ref bufferSize); if (result == 0 && entriesRead > 0) { IntPtr current = buffer; for (int i = 0; i < entriesRead; i++) { NETRESOURCE nr = (NETRESOURCE)Marshal.PtrToStructure(current, typeof(NETRESOURCE)); if (nr.dwDisplayType == 3) // 3代表网络计算机节点 { string computerName = nr.lpRemoteName?.TrimStart('\\'); if (!string.IsNullOrEmpty(computerName)) { computers.Add(computerName); } } current += Marshal.SizeOf(nr); } } } while (result == 0); } finally { Marshal.FreeHGlobal(buffer); } } finally { if (hEnum != IntPtr.Zero) { WNetCloseEnum(hEnum); } } return computers; } [StructLayout(LayoutKind.Sequential)] private struct NETRESOURCE { public int dwScope; public int dwType; public int dwDisplayType; public int dwUsage; public string lpLocalName; public string lpRemoteName; public string lpComment; public string lpProvider; } }
调用示例:
var lanComputers = NetworkBrowser.GetNetworkComputers();
二、获取指定机器的共享文件夹
通过WMI的Win32_Share类查询目标机器的磁盘共享,需引用System.Management程序集:
using System.Management; using System.Collections.Generic; public static List<string> GetMachineShares(string computerName) { List<string> sharePaths = new List<string>(); try { var scope = new ManagementScope($"\\\\{computerName}\\root\\cimv2"); scope.Connect(); var query = new ObjectQuery("SELECT * FROM Win32_Share WHERE Type = 0"); // Type=0表示磁盘类共享 var searcher = new ManagementObjectSearcher(scope, query); foreach (ManagementObject share in searcher.Get()) { string shareName = share["Name"].ToString(); sharePaths.Add($"\\\\{computerName}\\{shareName}"); } } catch (Exception ex) { // 捕获机器不可达、权限不足等异常 Console.WriteLine($"获取共享失败: {ex.Message}"); } return sharePaths; }
调用示例:
var sharedFolders = GetMachineShares("DESKTOP-ABC123");
三、遍历共享目录的文件/文件夹
拿到UNC路径后,直接使用System.IO的常规API即可遍历,和本地文件操作逻辑一致:
using System.IO; public static void TraverseShareDirectory(string uncPath) { try { // 遍历子目录 foreach (string dir in Directory.GetDirectories(uncPath)) { Console.WriteLine($"目录: {dir}"); TraverseShareDirectory(dir); // 递归遍历深层目录 } // 遍历文件 foreach (string file in Directory.GetFiles(uncPath)) { Console.WriteLine($"文件: {file}"); } } catch (UnauthorizedAccessException) { Console.WriteLine($"无权限访问路径: {uncPath}"); } catch (DirectoryNotFoundException) { Console.WriteLine($"路径不存在: {uncPath}"); } }
关键注意事项
- 网络发现开关:确保Windows系统的「网络发现」功能已启用,否则可能无法枚举到局域网内的机器。
- 权限处理:访问需要验证的共享时,可使用
WNetAddConnection2API提前建立带用户名密码的连接,避免权限异常。 - 异常捕获:枚举和遍历过程中必须处理机器离线、权限不足、路径不存在等异常,保证程序稳定性。
内容的提问来源于stack exchange,提问作者Zmuffin
相关产品推荐
相关产品推荐

