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 Win32Exception(apiRetVal);

                // 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 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));

                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.

        }

    }

Alternative Managed API:

Do you know one? Please contribute it!

Documentation