为什么WNetGetUniversalName在某些机器上因ERROR_NOT_SUPPORTED而失败?

时间:2014-04-16 13:56:08

标签: c# winapi pinvoke

我用这个绳子到达了最后。我有一些C#代码试图将包含映射到网络驱动器的驱动器号(例如“S:\”)的路径解析为UNC路径(例如“\\ server \ share \”)。我是通过P / Invoke使用WNetGetUniversalName来做这件事,但在我的一些同事的机器上(不是我的,烦人)我看到该函数一直失败,错误代码为ERROR_NOT_SUPPORTED。

以下是代码:

[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;
}

第一次调用WNetGetUniversalName时,我看到了ERROR_NOT_SUPPORTED返回值。就像我说的那样,它每次都在我的机器上运行,但它似乎总是在其他机器上失败。

更新:我应该补充一点,在所有情况下,使用的操作系统都是带有Service Pack 1的Windows 7 Enterprise x64。

更新2:我应该更加清楚我混淆的原因。该文档指出ERROR_NOT_SUPPORTED意味着没有网络提供商支持UNC名称。但是,UNC名称在我看过这个问题的每台机器上运行良好。我想知道是否有人之前已经看到这个和/或可能能够为ERROR_NOT_SUPPORTED返回提供其他可能的解释。

2 个答案:

答案 0 :(得分:3)

documentation表示此返回值表示:

  

dwInfoLevel参数设置为UNIVERSAL_NAME_INFO_LEVEL,但网络提供程序不支持UNC名称。 (没有网络提供商支持此功能。)

除此之外还有更多内容。

答案 1 :(得分:2)

知道了!经过一番挖掘,我找到了问题的根源。呼叫不起作用的机器安装了名为“Pismo File Mount”的网络提供商,显然是Pismo File Mount Audit Package的一部分。

我找到了已安装网络提供商的列表,如下所示:

  • 打开网络和共享中心。
  • 点击左侧窗格中的“更改适配器设置”。
  • 按ALT调出菜单栏,然后​​从“高级”菜单中选择“高级设置...”。
  • 转到“提供商订单”标签。

这就是我所看到的:

Screenshot of Provider Order tab in Advanced Settings

我能够通过以下方式解决问题:

  • 将“Pismo File Mount”移至提供商列表中“Microsoft Windows Network”下方。
  • 卸载Pismo文件装载审核包。

我仍然不理解我想要的问题,但至少我们有一些东西可以告诉客户他们是否遇到过这个问题。