Introduction
Two common requirements seem to have been missed from the .NET framework: enumerating network shares, and converting a local path to a UNC path. The shares could potentially be retrieved via WMI, but you can't guarantee that NT4 and 98 will have it installed. These classes provide a simple wrapper around the API calls necessary to retrieve this information.
Implementation
To retrieve the UNC path for a file on a mapped drive, call WNetGetUniversalName
. This doesn't work on Windows 95, but neither does the .NET framework, so I don't care!
If the path is on a local shared folder, WNetGetUniversalName
won't help. In this case, you need to call NetShareEnum
and look for a matching path. The function behaves completely differently across NT/2K/XP and 9x/ME, so there are two versions of this code.
- In the NT version, you may not have permissions to access the
SHARE_INFO_2
information, so the code will revert to the SHARE_INFO_1
structure. In this case, the path will not be available.
- On Windows 9x/ME/NT4, the server name (if any) must be prefixed with "\\". The code will check this, so you don't need to worry.
- On Windows 9x/ME, there is no way to resume the enumeration, so the code will return a maximum of 20 shares.
Classes
Share
Encapsulates information about a single network share, including the server name, share name, share type, local path and comment. Also has some utility methods to determine if it is a file-system share, whether it matches part of a local path, and returns the root directory.
ShareCollection
A strongly-typed read-only collection of Share
objects. Shares can be retrieved by index or by path, in which case the best match will be returned. Includes factory methods to return the shares for a specified computer, and static methods to return the UNC path and local share for a local path.
Interesting Note
The Windows 98 structure SHARE_INFO_50
is declared in the file SrvApi.h. Towards the top of the file, there is a line which reads #pragma pack(1)
. Although this looks like complete gobbledegook, it is actually important. The number in brackets specifies the packing for all structures in the file. According to MSDN, the alignment of a member will be on a boundary that is either a multiple of n or a multiple of the size of the member, whichever is smaller.
In the case of the SHARE_INFO_50
structure, the default packing, pads the structure to align the members on 8 byte boundaries. This meant that the size was calculated as 44 bytes, when it should be 42. Two extra padding bytes are added to the end of the structure to make the length a multiple of 4, the size of the native integer.
After tearing my hair out trying to work out why the size was wrong, and why taking two bytes off the end reduced the size by four bytes, I finally noticed the Pack
property of the StructLayoutAttribute
class. Adding Pack=1
to the attribute fixed the problems, and the code now works on Windows 98.
Demonstration
The testShares.cs file contains a sample console application which demonstrates the main functionality. The testShares.exe file is the compiled version of this sample.
Console.WriteLine("\nShares on local computer:");
ShareCollection shi = ShareCollection.LocalShares;
if (shi != null)
{
foreach(Share si in shi)
{
Console.WriteLine("{0}: {1} [{2}]",
si.ShareType, si, si.Path);
if (si.IsFileSystem)
{
try
{
System.IO.DirectoryInfo d = si.Root;
System.IO.DirectoryInfo[] Flds = d.GetDirectories();
for (int i=0; i < Flds.Length && i < 5; i++)
Console.WriteLine("\t{0} - {1}", i, Flds[i].FullName);
Console.WriteLine();
}
catch (Exception ex)
{
Console.WriteLine("\tError listing {0}:\n\t{1}\n",
si, ex.Message);
}
}
}
}
else
Console.WriteLine("Unable to enumerate the local shares.");
Console.WriteLine("{0} = {1}",
fileName, ShareCollection.PathToUnc(fileName));
Updates
- 25 September 2002 - Original Release
- 13 March 2003 -
- Changed the
ShareCollection
to inherit from System.Collections.ReadOnlyCollection
.
- Moved the P/Invoke code inside the
ShareCollection
class, and removed the internal Interop
class.
- Fixed the packing bug on Windows 9x. Note to self: When the C++ header file says
#pragma pack(1)
, don't ignore it!
- Added support for level 1 share enumeration on Windows 98, which is required to list shares on remote machines, but isn't documented in MSDN.
- 12 November 2003 - Bug fix
Credits
This code is (very) loosely based on a VB6 solution by Karl E. Peterson [http://www.mvps.org/vb].