10

In Delphi there is a function ExpandUNCFileName that takes in a filename and converts it into the UNC equivalent. It expands mapped drives and skips local and already expanded locations.

Samples

C:\Folder\Text.txt -> C:\Folder\Text.txt
L:\Folder\Sample.txt -> \\server\Folder1\Folder\Sample.txt Where L: is mapped to \\server\Folder1\
\\server\Folder\Sample.odf -> \server\Folder\Sample.odf

Is there a simple way to do this in C# or will I have to use windows api call WNetGetConnection and then manually check the ones that wouldn't get mapped?

Chris J
  • 2,160
  • 4
  • 16
  • 23

4 Answers4

6

Here's some C# code with a wrapper function LocalToUNC, which seems to work OK, though I haven't tested it extensively.

    [DllImport("mpr.dll")]
    static extern int WNetGetUniversalNameA(
        string lpLocalPath, int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize
    );

    // I think max length for UNC is actually 32,767
    static string LocalToUNC(string localPath, int maxLen = 2000)
    {
        IntPtr lpBuff;

        // Allocate the memory
        try
        {
            lpBuff = Marshal.AllocHGlobal(maxLen); 
        }
        catch (OutOfMemoryException)
        {
            return null;
        }

        try
        {
            int res = WNetGetUniversalNameA(localPath, 1, lpBuff, ref maxLen);

            if (res != 0)
                return null;

            // lpbuff is a structure, whose first element is a pointer to the UNC name (just going to be lpBuff + sizeof(int))
            return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(lpBuff));
        }
        catch (Exception)
        {
            return null;
        }
        finally
        {
            Marshal.FreeHGlobal(lpBuff);
        }
    }
Jack Culhane
  • 763
  • 7
  • 11
  • +1 because of `Marshal.ReadIntPtr(lpBuff)` to get at the string buffer. This is cleaner than the top example on pinvoke.net, where they do some shifty pointer arithmetic because they make the undocumented assumption that the string buffer is located directly behind the `UNIVERSAL_NAME_INFO` struct. – herzbube Apr 14 '14 at 16:32
5

P/Invoke WNetGetUniversalName().

I've done it modifying this code from www.pinvoke.net.

Jay Riggs
  • 53,046
  • 9
  • 139
  • 151
2

There is no built-in function in the BCL which will do the equivalent. I think the best option you have is pInvoking into WNetGetConnection as you suggested.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
0

Try this code, is written in Delphi .Net

you must translate it to c #

function WNetGetUniversalName; external;
[SuppressUnmanagedCodeSecurity, DllImport(mpr, CharSet = CharSet.Ansi, SetLastError = True, EntryPoint = 'WNetGetUniversalNameA')]


function ExpandUNCFileName(const FileName: string): string;

function GetUniversalName(const FileName: string): string;
const
UNIVERSAL_NAME_INFO_LEVEL = 1;    
var
  Buffer: IntPtr;
  BufSize: DWORD;
begin
  Result := FileName;
  BufSize := 1024;
  Buffer := Marshal.AllocHGlobal(BufSize);
  try
    if WNetGetUniversalName(FileName, UNIVERSAL_NAME_INFO_LEVEL,
      Buffer, BufSize) <> NO_ERROR then Exit;
    Result := TUniversalNameInfo(Marshal.PtrToStructure(Buffer,
      TypeOf(TUniversalNameInfo))).lpUniversalName;
  finally
    Marshal.FreeHGlobal(Buffer);
  end;
end;

begin
  Result :=System.IO.Path.GetFullPath(FileName);
  if (Length(Result) >= 3) and (Result[2] = ':') and (Upcase(Result[1]) >= 'A')
    and (Upcase(Result[1]) <= 'Z') then
    Result := GetUniversalName(Result);
end;

Bye.

RRUZ
  • 134,889
  • 20
  • 356
  • 483