Like this Blog on FB

Monday, May 10, 2010

Getting the UNC Path of the Network Drives using DllImport, C# and .NET Framework

Folks,
Back again. Once again I was lazy for the past month and half and was dull at the bloggers end. I have been doing more productive work for the last couple of weeks and hence there were no posts from me. However, finally I am at writing a post. People who know me closely and have moved closely with me, please hold your hearts strong because this is a head-toe technical posting and it is related to C#. Yes, finally here I go with a techie posting YAY!. Since the post is more educational I chose to use more formal 'language and format' of writing.

Problem:

One of the requirements of the product that I was doing is like this: There will be a screen in a windows based application and it consists of a combo box. The combo box should display the network drives of the computer. For those who are less literate about network drives; Network Drives are those locations that are mapped to a drive or folder in another system which can be accessed over network. Usually it is often painful to manually navigate to the network location and access the files there. So windows allows us to create network drives on our machines such that we can access the desired network location with just one single click.

How to create a Network Drive?

The creation of network drives is a very simple process.
  • Open My Computer --> Select tools from the menu bar--> Select the Map Network Drive option.
  • This opens a window which has a combo box with the existing network drives and non networking drives.
  • Upon selecting a drive the text box below the drop down list will display the path that the network is mapped to.
  • Once you select the drive letter from the combo box , Enter the Network path in the text box and click Finish.
  • Now you should be able to view the network drives in the my computer screen.

Solution to the Problem:

If you have ever worked on .NET you would certainly know how vast is the base class library of .NET. We can do many things with it. Yet, we cannot do everything using just the .NET framework and the BCL. Windows OS( XP,VISTA,WINDOWS 7) uses a special assembly called 'mpr.dll". mpr.dll is a module containing functions that are used to handle communication between the Windows operating system and the installed network providers. This assembly basically takes care of the relation between Drive Name Versus the Network Path. So we use the same .dll to fetch us the information that we need. The assembly should be referred as an external assembly and values should be passed to it. Inorder to do this we use the DllImport attribute method to point to the mpr.dll. We must point the Drive letters to the external Dll this shoud be done with the help of MarshallAs attribute.

Have a look at the following code.

namespace Srikanth.Samples
{
public static class Pathing
{
[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);
///
/// Given a path, returns the UNC path or the original. (No exceptions
/// are raised by this function directly). For example, "P:\2008-02-29"
/// might return: "\\networkserver\Shares\Photos\2008-02-09"
///

/// The path to convert to a UNC Path
/// A UNC path. If a network drive letter is specified, the
/// drive letter is converted to a UNC or network path. If the
/// originalPath cannot be converted, it is returned unchanged.

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;
}
}
}
As far as my requirement is considered I have a combo box which is currently used to display all the drives that are there in my computer. Irrespective of whether the drive is a network drive or a local drive the current combo box displays all the drives. My requirement is to only display the network drives that are available there in my system. How do I do this? Thanks to the .NET framework, the DriveInfo class of the framework allows you to search through all the drives that are available on the machine. All that I needed to do was just ,run a foreach loop which looks for the Drives which are of network type.

This is as simple as this:


DriveInfo[] allDrives = DriveInfo.GetDrives();

foreach (DriveInfo d in allDrives)
{
if (d.DriveType == DriveType.Network)
{
cmbbxDrive.Items.Add(d.ToString());
}
}

Doing this will allow me to fetch the only network drives into the combo box. Upon selecting one of the drives the Drive's Letter will be sent as a parameter(LPStr) to the MarshalAs method. The "Mpr.dll" will now do the respective task and returns us the string which is essentially the path of Network Drive and the Folder eg:"\\MyServer\MyFolder". As per the need one can split the path further and save into Database. Otherwise you can send the one who assigned you the task a message saying "MISSION ACCOMPLISHED"


Hope this is better than the love tips post!

Cheers,
Sriki