映射的网络驱动器无法在C#中列出。

9
我试图在我的应用程序中列出所有本地驱动器,DriveInfo.GetDrives 返回本地驱动器的字母,但我也需要映射的驱动器。

目前我有:C:,D:和G:(硬盘),E:和F:(CD),以及S:和Z:(映射的网络驱动器)。 (是的,它们在Windows资源管理器和Total Commander中都可见。) 但只有C、D、E、F、G可以通过编程方式检索到。

我还尝试了Environment.GetLogicalDrives()GetLogicalDriveStrings (pInvoke)FindFirstVolumeFindNextVolumen(pInvoke)。我试图在注册表中查找映射驱动器列表。没有任何作用,只有硬盘和CD字母被检索到。

没有任何异常发生,直接WinAPI调用中也没有指示错误,现在我卡住了。这是某种安全设置吗?无论我看哪里,人们都说DriveInfo.GetDrives应该返回映射的驱动器。这是真的吗?

我正在使用Vista Home Pro操作系统。该应用程序是在本地计算机上运行的,并且也是使用Visual Studio 2008在此构建的。
以下是我所使用的内容,但它非常简单,不可能出现我做错了什么的情况:
foreach (System.IO.DriveInfo di in System.IO.DriveInfo.GetDrives())
    Console.WriteLine(di.Name);

结果: C:\ D:\ E:\ F:\ G:\ 按任意键继续. . .

我该如何使其工作?


你是在用户模式下运行还是在服务模式下运行? - Brett Allen
在用户模式下。完全正常的控制台应用程序或WinForm应用程序。 - Zolka
2个回答

9

好的,我找到了如何在Vista上获取已断开连接的驱动器。虽然不容易,但确实可行:

首先,您需要以下WinAPI函数的pInvoke定义:

  • WNetOpenEnum
  • WNetEnumResource
  • WNetCloseEnum

还需要一些结构体和枚举。

然后您需要多次调用这些函数,最终得到列表。下面是代码,请注意,它很长:

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

    [DllImport("MPR.dll", CharSet = CharSet.Auto)]
    static extern int WNetOpenEnum(RESOURCE_SCOPE dwScope, RESOURCE_TYPE dwType, RESOURCE_USAGE dwUsage,
        [MarshalAs(UnmanagedType.AsAny)][In] object lpNetResource, out IntPtr lphEnum);

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

    public enum RESOURCE_SCOPE : uint
    {
        RESOURCE_CONNECTED = 0x00000001,
        RESOURCE_GLOBALNET = 0x00000002,
        RESOURCE_REMEMBERED = 0x00000003,
        RESOURCE_RECENT = 0x00000004,
        RESOURCE_CONTEXT = 0x00000005
    }
    public enum RESOURCE_TYPE : uint
    {
        RESOURCETYPE_ANY = 0x00000000,
        RESOURCETYPE_DISK = 0x00000001,
        RESOURCETYPE_PRINT = 0x00000002,
        RESOURCETYPE_RESERVED = 0x00000008,
    }
    public enum RESOURCE_USAGE : uint
    {
        RESOURCEUSAGE_CONNECTABLE = 0x00000001,
        RESOURCEUSAGE_CONTAINER = 0x00000002,
        RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
        RESOURCEUSAGE_SIBLING = 0x00000008,
        RESOURCEUSAGE_ATTACHED = 0x00000010,
        RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
    }
    public enum RESOURCE_DISPLAYTYPE : uint
    {
        RESOURCEDISPLAYTYPE_GENERIC = 0x00000000,
        RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001,
        RESOURCEDISPLAYTYPE_SERVER = 0x00000002,
        RESOURCEDISPLAYTYPE_SHARE = 0x00000003,
        RESOURCEDISPLAYTYPE_FILE = 0x00000004,
        RESOURCEDISPLAYTYPE_GROUP = 0x00000005,
        RESOURCEDISPLAYTYPE_NETWORK = 0x00000006,
        RESOURCEDISPLAYTYPE_ROOT = 0x00000007,
        RESOURCEDISPLAYTYPE_SHAREADMIN = 0x00000008,
        RESOURCEDISPLAYTYPE_DIRECTORY = 0x00000009,
        RESOURCEDISPLAYTYPE_TREE = 0x0000000A,
        RESOURCEDISPLAYTYPE_NDSCONTAINER = 0x0000000B
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct NetResource
    {
        public RESOURCE_SCOPE dwScope;
        public RESOURCE_TYPE dwType;
        public RESOURCE_DISPLAYTYPE dwDisplayType;
        public RESOURCE_USAGE dwUsage;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
        public string lpLocalName;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
        public string lpRemoteName;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
        public string lpComment;
        [MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)]
        public string lpProvider;
    }

    static System.Collections.Generic.Dictionary<string, NetResource> WNetResource(object resource)
    {
        System.Collections.Generic.Dictionary<string, NetResource> result = new System.Collections.Generic.Dictionary<string, NetResource>();

        int iRet;
        IntPtr ptrHandle = new IntPtr();
        try
        {
            iRet = WNetOpenEnum(
                RESOURCE_SCOPE.RESOURCE_REMEMBERED, RESOURCE_TYPE.RESOURCETYPE_DISK, RESOURCE_USAGE.RESOURCEUSAGE_ALL,
                resource, out ptrHandle);
            if (iRet != 0)
                return null;

            int entries = -1;
            int buffer = 16384;
            IntPtr ptrBuffer = Marshal.AllocHGlobal(buffer);
            NetResource nr;

            iRet = WNetEnumResource(ptrHandle, ref entries, ptrBuffer, ref buffer);
            while ((iRet == 0) || (entries > 0))
            {
                Int32 ptr = ptrBuffer.ToInt32();
                for (int i = 0; i < entries; i++)
                {
                    nr = (NetResource)Marshal.PtrToStructure(new IntPtr(ptr), typeof(NetResource));
                    if (RESOURCE_USAGE.RESOURCEUSAGE_CONTAINER == (nr.dwUsage
                        & RESOURCE_USAGE.RESOURCEUSAGE_CONTAINER))
                    {
                        //call recursively to get all entries in a container
                        WNetResource(nr);
                    }
                    ptr += Marshal.SizeOf(nr);
                    result.Add(nr.lpLocalName, nr);
                }

                entries = -1;
                buffer = 16384;
                iRet = WNetEnumResource(ptrHandle, ref entries, ptrBuffer, ref buffer);
            }

            Marshal.FreeHGlobal(ptrBuffer);
            iRet = WNetCloseEnum(ptrHandle);
        }
        catch (Exception)
        {
        }

        return result;
    }
    public static System.Collections.Generic.Dictionary<string, NetResource> WNetResource()
    {
        return WNetResource(null);
    }

您需要调用WNetResource()函数,然后您将获得驱动器列表。(还有蛋糕 :-))


4

Environment.GetLogicalDrives()DriveInfo.GetDrives() 都返回了我所有的网络驱动器。

你的应用程序是否以不同的用户身份运行(例如 asp.net 网站)?如果是,这些驱动器是否实际上被映射到该用户?你可能会发现这些驱动器对于你来说是已经映射好的,但它们实际上并没有被映射到你的应用程序所运行的用户。


不,这是一个WinForm应用程序,并且我没有更改用户。 这可能是因为UAC(我保持打开)使用普通用户启动我的应用程序,而映射的驱动器链接到我的真实(管理员)用户吗?我怀疑...但也许是这样。 - Zolka
1
我有所怀疑,通常不需要授予管理员访问权限才能查看文件共享。你可以尝试以管理员身份运行应用程序来查看。你可以查看一下 System.Security.Principal.WindowsIdentity.GetCurrent().Name,它会告诉你当前正在运行的用户,以确保没有问题。 - fyjham
我尝试了关闭UAC,但仍然不起作用。我从应用程序中检查了当前用户,它与我使用的相同。 顺便说一下,映射的驱动器已经断开连接。我不认为这应该有任何区别,但也许有所帮助。 - Zolka
是的,如果映射的驱动器断开连接,那将会有所不同。如果您的网络驱动器离线,则实际上没有连接,因此不是逻辑驱动器。您必须进入更混乱的方式才能做到这一点。我用过的唯一方法(WNetRestoreConnectionW)在其MSDN页面上有一个大的“自Windows Vista起不可用”的标志,所以我不确定您该如何操作。 - fyjham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接