24

I'm trying to detect if the directory exists, but in this particular situation my directory is a network location. I used VB.NET's My.Computer.FileSystem.DirectoryExists(PATH) and the more general System.IO.Directory.Exists(PATH), and in both cases, the system response is false. I checked and the PATH exists, I can view it in MyComputer Folder. If I debug the program, and watch the My.Computer.FileSystem.Drives variable, the network location does not appear in that list.

UPDATE: I checked and in Windows XP the Response is True, but not in Windows 7.

UPDATE2: I tested both proposed solutions but I still have the same problem, on the image below you will see that I can access using Explorer but my program cannot. The GetUNCPath function returns a valid path (no errors), but Directory.Exists stil returns false.

I also tried with the UNC path "\\Server\Images"; same result.

enter image description here

UPDATE3: If I cannot link with a network drive, how can I link to UNC path directly?. I discovered that if i run VS in normal mode, it works, but my software must run in administrator mode. So, there is any way to check the existence of a network directory as administrator?

Natalia
  • 470
  • 2
  • 5
  • 12

4 Answers4

17

If UAC is turned on, mapped network drives only exist "by default" in the session they are mapped: Normal or elevated. If you map a network drive from explorer, then run VS as admin, the drive will not be there.

You need to enable what MS calls "linked connections": HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System: EnableLinkedConnections (REG_DWORD) = 0x1

Background Information about "two logon sessions" with UAC: http://support.microsoft.com/kb/937624/en-us

Martin Binder
  • 1,066
  • 7
  • 5
  • I run the VS in normal account and it works perfect, I created the EnableLinkedConnections key on HKEY_LOCAL_MACHINE, but I'm still getting the error when I run VS in administrator mode. – Natalia Jul 22 '13 at 14:45
  • wait, i look on internet and they said that i must restart the computer, so i will check that first. – Natalia Jul 22 '13 at 15:11
  • @Natalia correct - a system restart should be performed any time after modifying the registry to ensure the changes take place. Did that resolve the issue? – Saggio Jul 22 '13 at 16:20
  • We had trouble accessing '\\computername\folder' but after applying this registry setting (and as it says on internet restart the computer) things worked. Thanks a lot! – Njal Jul 11 '14 at 12:26
  • What happens if I just turn off `UAC`? – wonsuc Dec 21 '22 at 04:32
8

When you use System.IO.Directory.Exists, it only lets you know that it couldn't find the directory, but this could be because the directory doesn't actually exist or because the user doesn't have sufficient access rights to the directory.

In order to resolve this, we add a secondary test after Directory.Exists fails to obtain the real reason for the directory's absence and we have wrapped this into a global method that is used in place of the standard Directory.Exists method:

''' <summary>
''' This method tests to ensure that a directory actually does exist. If it does not, the reason for its 
''' absence will attempt to be determined and returned. The standard Directory.Exists does not raise 
''' any exceptions, which makes it impossible to determine why the request fails.
''' </summary>
''' <param name="sDirectory"></param>
''' <param name="sError"></param>
''' <param name="fActuallyDoesntExist">This is set to true when an error is not encountered while trying to verify the directory's existence. This means that 
''' we have access to the location the directory is supposed to be, but it simply doesn't exist. If this is false and the directory doesn't exist, then 
''' this means that an error, such as a security error, was encountered while trying to verify the directory's existence.</param>
Public Function DirectoryExists(ByVal sDirectory As String, ByRef sError As String, Optional ByRef fActuallyDoesntExist As Boolean = False) As Boolean
    ' Exceptions are partially handled by the caller

    If Not IO.Directory.Exists(sDirectory) Then
        Try
            Dim dtCreated As Date

            ' Attempt to retrieve the creation time for the directory. 
            ' This will usually throw an exception with the complaint (such as user logon failure)
            dtCreated = Directory.GetCreationTime(sDirectory)

            ' Indicate that the directory really doesn't exist
            fActuallyDoesntExist = True

            ' If an exception does not get thrown, the time that is returned is actually for the parent directory, 
            ' so there is no issue accessing the folder, it just doesn't exist.
            sError = "The directory does not exist"
        Catch theException As Exception
            ' Let the caller know the error that was encountered
            sError = theException.Message
        End Try

        Return False
    Else
        Return True
    End If
End Function
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
competent_tech
  • 44,465
  • 11
  • 90
  • 113
  • @Natalia: The only thing I can think of is that the app is not running as the user you think it is and thus not getting the mapped drive. You can see who the exe is operating as by adding this code: Debug.WriteLine(System.Security.Principal.WindowsIdentity.GetCurrent().Name) – competent_tech Jul 16 '13 at 19:09
  • I wrote that line of code, and the user that is running the application is my user. This user is administrator. I think that this is not the problem. – Natalia Jul 17 '13 at 13:12
  • I have the same problem, and the problem comes from vs running as a different account. Running as administrator is different than running with an account in administrator group. It is easy to check: Try to run visual studio in normal account, not as admin. – Eric Bole-Feysot Jul 19 '13 at 05:56
  • @Qwench i run the VS in normal account and it works perfect, but i need to run my code in administrator mode. So, How I can fix it? – Natalia Jul 22 '13 at 14:27
  • @Natalia: If you run your app in administrator mode and you use an administrator that is local to the machine you are running on, it will not have access to network drives. In order to accomplish your goal, you must run as network user that has both access to the network drives and administrator privileges on the local machine. Assuming sufficient privileges, you can add network users to the local machine's administrator group in order to meet this need. – competent_tech Jul 22 '13 at 17:45
  • @Natalia: DirectoryInfo accepts unc. See [here](http://stackoverflow.com/questions/5152647/how-to-quickly-check-if-unc-path-is-available) – Eric Bole-Feysot Aug 19 '13 at 11:55
5
public static class MappedDriveResolver
    {
        [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern int WNetGetConnection([MarshalAs(UnmanagedType.LPTStr)] string localName, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, ref int length);
        public static string GetUNCPath(string originalPath)
        {
            StringBuilder sb = new StringBuilder(512);
            int size = sb.Capacity;

            // look for the {LETTER}: combination ...
            if (originalPath.Length > 2 && originalPath[1] == ':')
            {
                // don't use char.IsLetter here - as that can be misleading
                // the only valid drive letters are a-z && A-Z.
                char c = originalPath[0];
                if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
                {
                    int error = WNetGetConnection(originalPath.Substring(0, 2), sb, ref size);
                    if (error == 0)
                    {
                        DirectoryInfo dir = new DirectoryInfo(originalPath);
                        string path = Path.GetFullPath(originalPath).Substring(Path.GetPathRoot(originalPath).Length);
                        return Path.Combine(sb.ToString().TrimEnd(), path);
                    }
                }
            }    
            return originalPath;
        }
    }

To use it, pass in a Network folder path, convert to UNC folder path and see if the folder exists:

File.Exists(MappedDriveResolver.GetUNCPath(filePath));

Edit:

I saw your second edit and the only difference (in my Windows7) when I view a network drive I see Computer > Images (\\xyzServer). Is your PC's name Equipo? is that team in spanish? is that your PC? I tried to reproduce your problem but it works for me:

enter image description here

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
  • Yes, my Computer Name is "Equipo", i am from argentina. I dont know why my Visual Studio it not recognize the network drive on my Windows 7. This problem is driving me crazy. – Natalia Jul 17 '13 at 13:16
2

Adding to this, I needed to do an 'Exists' check on network shares that could listed, but the account did not have permission to access, so Directory.Exists would return False.

Various solutions posted did not work for me, so here is my own:

public static bool DirectoryVisible(string path)
{
    try
    {
        Directory.GetAccessControl(path);
        return true;
    }
    catch (UnauthorizedAccessException)
    {
        return true;
    }
    catch
    {
        return false;
    }
}
WhoIsRich
  • 4,053
  • 1
  • 33
  • 19