WNetGetUniversalName (advapi32)
Last changed: -24.132.191.153

.
Summary
TODO - a short description

C# Signature:

[DllImport("mpr.dll")]
[return:MarshalAs(UnmanagedType.U4)]
static extern int WNetGetUniversalName(
    string lpLocalPath,
    [MarshalAs(UnmanagedType.U4)] int dwInfoLevel,
    IntPtr lpBuffer,
    [MarshalAs(UnmanagedType.U4)] ref int lpBufferSize);

VB Signature:

Declare Function WNetGetUniversalName Lib "advapi32.dll" (TODO) As TODO

Constants:

const int UNIVERSAL_NAME_INFO_LEVEL = 0x00000001;
const int REMOTE_NAME_INFO_LEVEL = 0x00000002;

const int ERROR_MORE_DATA = 234;
const int NOERROR = 0;

Wrapper

    using System.Runtime.InteropServices;

    static string GetUniversalName(string localPath)
    {
        // The return value.
        string retVal = null ;

        // The pointer in memory to the structure.
        IntPtr buffer = IntPtr.Zero;

        // Wrap in a try/catch block for cleanup.
        try
        {
        // First, call WNetGetUniversalName to get the size.
        int size = 0;

        // Make the call.
        // Pass IntPtr.Size because the API doesn't like null, even though
        // size is zero.  We know that IntPtr.Size will be
        // aligned correctly.
        int apiRetVal = WNetGetUniversalName(localPath, UNIVERSAL_NAME_INFO_LEVEL, (IntPtr) IntPtr.Size, ref size);

        // If the return value is not ERROR_MORE_DATA, then
        // raise an exception.
        if (apiRetVal != ERROR_MORE_DATA)
            // Throw an exception.
            throw new Win32Exception(apiRetVal);

        // Allocate the memory.
        buffer = Marshal.AllocCoTaskMem(size);

        // Now make the call.
        apiRetVal = WNetGetUniversalName(localPath, UNIVERSAL_NAME_INFO_LEVEL, buffer, ref size);

        // If it didn't succeed, then throw.
        if (apiRetVal != NOERROR)
            // Throw an exception.
            throw new Win32Exception(apiRetVal);

        // Now get the string.  It's all in the same buffer, but
        // the pointer is first, so offset the pointer by IntPtr.Size
        // and pass to PtrToStringAuto.
        retVal = Marshal.PtrToStringAuto(new IntPtr(buffer.ToInt64() + IntPtr.Size));
        }
        finally
        {
        // Release the buffer.
        Marshal.FreeCoTaskMem(buffer);
        }

        // First, allocate the memory for the structure.

        // That's all folks.
        return retVal;
    }

Notes:

Note by Günter Prossliner 2005-08-29

PtrToStringAuto doesn't work on my system. I have tested in on a clean WindowsXP professional maschine. The PtrToStringAuto function just returns garbage. After stepping into the function with the debugger I was looking a the Memory - Windows pointing to the address of "buffer". What I've seen there was a "normal" zero - terminated ANSI String.

After i have changed

retVal = Marshal.PtrToStringAuto(new IntPtr(buffer.ToInt64() + IntPtr.Size));

into

retVal = Marshal.PtrToStringAnsi(new IntPtr(buffer.ToInt64() + IntPtr.Size), size);

all worked fine.

If you take a look at the IL - Code of Marshal.PtrToStringAuto(IntPtr) you can see that this function calls 'kernel32:lstrlen' and 'kernel32:lstrcpy' using a buffer (StringBuilder) with the size of lstrlen.

The code of Marshal.PtrToStringAuto(IntPtr, Int32 size) looks quite different: It checks out the Marshal.SystemDefaultCharSize field and simply calls 'PtrToStringAnsi' or 'PtrToStringUni'.

Tips & Tricks:

Please add some!

Sample Code:

/* This needs cleaning up -- errr but I'm paid by the hour so I don't have the time. I mostly ripped the wrapper and modified it. It provides an alternative to pointer arithmetic though...*/
/*
typedef struct _REMOTE_NAME_INFO
{
    LPTSTR lpUniversalName;
    LPTSTR lpConnectionName;
    LPTSTR lpRemainingPath;
} REMOTE_NAME_INFO;
*/

[StructLayout(LayoutKind.Sequential)]
struct _REMOTE_NAME_INFO
{
    public IntPtr lpUniversalName;
    public IntPtr lpConnectionName;
    public IntPtr lpRemainingPath;
}

public struct RemoteNameInfo
{
    public string universalName;
    public string connectionName;
    public string remainingPath;
}

public class WNet
{
    const int UNIVERSAL_NAME_INFO_LEVEL = 0x00000001;
    const int REMOTE_NAME_INFO_LEVEL = 0x00000002;

    const int ERROR_MORE_DATA = 234;
    const int NOERROR = 0;

    [DllImport("mpr.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.U4)]
    private static extern int WNetGetUniversalNameW(
        string lpLocalPath,
        [MarshalAs(UnmanagedType.U4)] int dwInfoLevel,
        IntPtr lpBuffer,
        [MarshalAs(UnmanagedType.U4)] ref int lpBufferSize);


    public static RemoteNameInfo GetRemoteNameInfo(string localPath)
    {
        // The return value.
        RemoteNameInfo retVal;
        _REMOTE_NAME_INFO rni;

        // The pointer in memory to the structure.
        IntPtr buffer = IntPtr.Zero;

        // Wrap in a try/catch block for cleanup.
        try
        {
            // First, call WNetGetUniversalName to get the size.
            int size = 0;

            // Make the call.
            // Pass IntPtr.Size because the API doesn't like null, even though
            // size is zero.  We know that IntPtr.Size will be
            // aligned correctly.
            int apiRetVal = WNetGetUniversalNameW(localPath, REMOTE_NAME_INFO_LEVEL, (IntPtr)IntPtr.Size, ref size);

            // If the return value is not ERROR_MORE_DATA, then
            // raise an exception.
            if (apiRetVal != ERROR_MORE_DATA)
                // Throw an exception.
                throw new System.ComponentModel.Win32Exception();

            // Allocate the memory.
            buffer = Marshal.AllocCoTaskMem(size);

            // Now make the call.
            apiRetVal = WNetGetUniversalNameW(localPath, REMOTE_NAME_INFO_LEVEL, buffer, ref size);

            // If it didn't succeed, then throw.
            if (apiRetVal != NOERROR)
                // Throw an exception.
                throw new System.ComponentModel.Win32Exception();

            // Now get the string.  It's all in the same buffer, but
            // the pointer is first, so offset the pointer by IntPtr.Size
            // and pass to PtrToStringAuto.
            //retVal = Marshal.PtrToStringAuto(new IntPtr(buffer.ToInt64() + IntPtr.Size));

            rni = (_REMOTE_NAME_INFO)Marshal.PtrToStructure(buffer, typeof(_REMOTE_NAME_INFO));

            retVal.connectionName = Marshal.PtrToStringAuto(rni.lpConnectionName);
            retVal.remainingPath = Marshal.PtrToStringAuto(rni.lpRemainingPath);
            retVal.universalName = Marshal.PtrToStringAuto(rni.lpUniversalName);

            return retVal;
        }
        finally
        {
            // Release the buffer.
            Marshal.FreeCoTaskMem(buffer);
        }

        // First, allocate the memory for the structure.
        // That's all folks.
    }
}

.NET Use in VB

by Mike Gerbi

12/05/2007

Summary
This utilizes the WNetGetUniversalName method in MPR.dll. Once implemented, all you have to do is create an instance of the MPR_DotNET_Version class and use the GetUniversalName method. You can also add on to this class for other functionality if you choose. Hope this helps.

Make A New Class

Imports System.Runtime.InteropServices

Namespace Custom.Win32

    'You can add more functionality from this DLL in this namespace and import it in future projects to get everything.
    Public Class MPR_DotNET_Version
    Private bufSize As Integer = 1000
    Private myPath As String = ""
    Private lpBuffer As IntPtr = Marshal.AllocHGlobal(bufSize)

    Public Enum INFO_LEVEL As Integer
        UNIVERSAL_NAME_INFO_LEVEL = 1
        REMOTE_NAME_INFO_LEVEL = 2
    End Enum

    Public Sub New(ByVal path As String)
        myPath = path
    End Sub

    Public Function GetUnivseralName() As String
        Dim uname As New UNIVERSAL_NAME_INFO

        Try
        Dim result As String = myPath
        Dim ret As Int32 = GetUName(result, INFO_LEVEL.UNIVERSAL_NAME_INFO_LEVEL, lpBuffer, bufSize)

        If ret = 0 Then
            Marshal.PtrToStructure(lpBuffer, uname)
        ElseIf ret = 2250 Then
            Throw New ArgumentException("Not Connected")
        End If
        Catch ex As Exception
        MsgBox(ex.Message)
        Finally
        Marshal.FreeHGlobal(lpBuffer)
        End Try

        Return uname.UniversalName.ToString

    End Function
    <DllImport("mpr.dll", Entrypoint:="WNetGetUniversalName", CharSet:=CharSet.Auto, SetLastError:=False)> _
    Private Shared Function GetUName(ByVal Path As String, ByVal outName As INFO_LEVEL, _
        ByVal bObj As IntPtr, ByRef bSize As Integer) As Integer

    End Function

    End Class

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto), Serializable()> Class UNIVERSAL_NAME_INFO
    <MarshalAs(UnmanagedType.LPTStr)> Public UniversalName As String
    <MarshalAs(UnmanagedType.LPTStr)> Public ConnectionName As String
    <MarshalAs(UnmanagedType.LPTStr)> Public RemainingPath As String

    End Class

End Namespace

Create An instance

Imports ScanningTools.Custom.Win32

Public Sample Class

Private path as String

Public Sub GetPath()

    Dim result As DialogResult = mainFolderBrowserDialog.ShowDialog
        If result = Windows.Forms.DialogResult.OK Then
        Dim dirInfo As DirectoryInfo = New DirectoryInfo(mainFolderBrowserDialog.SelectedPath)
        path = mainFolderBrowserDialog.SelectedPath

           'Here I get the UNC path and use it later in another routine.
        Dim UNI As MPR_DotNET_Version = New MPR_DotNET_Version(path)
        path = UNI.GetUnivseralName

        For Each f As FileInfo In dirInfo.GetFiles
            If f.Extension = ".txt" Then
            TextFileListView.Items.Add(f.Name)
            ElseIf f.Extension = ".pdf" Then
            PDFListView.Items.Add(f.Name)
            End If
        Next

        ElseIf result = Windows.Forms.DialogResult.Cancel Then
        Me.Close()
        Else
        Throw New System.Exception
        End If

    Catch ex As System.Exception
        MsgBox(ex.Message)
        WriteToErrorLog(ex)
    End Try

End Sub

Alternative Managed API:

Do you know one? Please contribute it!

Documentation