Question

I've reached the end of my rope with this one. I have some C# code that's trying to resolve paths containing drive letters mapped to network drives (e.g. "S:\") to UNC paths (e.g. "\\server\share\"). I'm doing this using WNetGetUniversalName via P/Invoke, but on some of my colleagues' machines (not mine, annoyingly) I'm seeing the function consistently fail with the error code ERROR_NOT_SUPPORTED.

Here's the code:

[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.U4)]
static extern int WNetGetUniversalName(
    string lpLocalPath,
    [MarshalAs(UnmanagedType.U4)] int dwInfoLevel,
    IntPtr lpBuffer,
    [MarshalAs(UnmanagedType.U4)] ref int lpBufferSize);
/// <summary>
///   Gets the UNC path for the path passed in.
/// </summary>
/// <param name="path">The path for which we want the UNC path.</param>
/// <returns>The UNC path.  Returns empty string if an error has occurred. </returns>
public static string GetUniversalPath(string path)
{
  const int UNIVERSAL_NAME_INFO_LEVEL = 0x00000001;
  const int ERROR_MORE_DATA = 234;
  const int NOERROR = 0;

  string retVal = null;

  // Pointer to the memory buffer to hold the result.
  IntPtr buffer = IntPtr.Zero;

  try
  {
    // First, call WNetGetUniversalName to get the size.
    // Passing (IntPtr)IntPtr.Size as the third parameter because WNetGetUniversalName doesn't
    // like NULL, and IntPtr.Size will always be a properly-aligned (if not actually valid)
    // IntPtr value.
    int size = 0;
    int apiRetVal = WNetGetUniversalName(path, UNIVERSAL_NAME_INFO_LEVEL, (IntPtr)IntPtr.Size, ref size);

    if (apiRetVal == ERROR_MORE_DATA)
    {
      // Allocate the memory.
      buffer = Marshal.AllocCoTaskMem(size);

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

      if (apiRetVal == NOERROR)
      {
        // 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 PtrToStringAnsi.
        retVal = Marshal.PtrToStringAuto(new IntPtr(buffer.ToInt64() + IntPtr.Size), size);
        retVal = retVal.Substring(0, retVal.IndexOf('\0'));
      }
    }
  }
  catch 
  {
    // I know swallowing exceptions is nasty...
    retVal = "";
  }
  finally
  {
    Marshal.FreeCoTaskMem(buffer);
  }

  return retVal;
}

I'm seeing the ERROR_NOT_SUPPORTED return value the first time WNetGetUniversalName is called. Like I said, it works every time on my machine but it always seems to fail on others.

UPDATE: I should probably add that in all cases, the operating system in use is Windows 7 Enterprise x64 with Service Pack 1.

UPDATE 2: I should have been clearer about the reason for my confusion. The documentation states that ERROR_NOT_SUPPORTED means that no network providers support UNC names. However, UNC names work fine on every machine where I've seen this problem. I'm wondering if anyone has seen this before and/or might be able to provide other possible explanations for ERROR_NOT_SUPPORTED being returned.

Was it helpful?

Solution 2

Got it! After a bit of digging, I found the source of the problem. The machines where the call didn't work had a network provider called "Pismo File Mount" installed, apparently as part of something called the Pismo File Mount Audit Package.

I found the list of installed network providers as follows:

  • Open Network and Sharing Center.
  • Click "Change adapter settings" in the pane on the left.
  • Press ALT to bring up the menu bar, then select "Advanced Settings..." from the "Advanced" menu.
  • Go to the "Provider Order" tab.

This is what I saw:

Screenshot of Provider Order tab in Advanced Settings

I was able to resolve the problem by either:

  • Moving "Pismo File Mount" down below "Microsoft Windows Network" in the list of providers.
  • Uninstalling the Pismo File Mount Audit Package.

I still don't understand the problem as well as I'd like, but at least we have something to tell customers if they run into it.

OTHER TIPS

The documentation says that this return value means:

The dwInfoLevel parameter is set to UNIVERSAL_NAME_INFO_LEVEL, but the network provider does not support UNC names. (None of the network providers support this function.)

There's not much more to add to that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top