Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 调用WNetGetUniversalName后Marshal.PtrToStringAuto出现问题_C#_Marshalling - Fatal编程技术网

C# 调用WNetGetUniversalName后Marshal.PtrToStringAuto出现问题

C# 调用WNetGetUniversalName后Marshal.PtrToStringAuto出现问题,c#,marshalling,C#,Marshalling,下面是我获取通用路径的函数。我在这个主题上发现了各种相互冲突的帖子,这已经经过了多次迭代,但是这个函数通常是有效的。但是,大约有5%的时间它会导致应用程序崩溃。错误消息表明它可能已损坏内存。我找不到理由。在调试器下运行c#应用程序时,问题永远不会发生,但是如果我在错误发生后附加到进程,那么我可以查看WNetGetUniversalName返回的数据,它看起来与没有崩溃时完全相同。我想知道是什么原因造成的 public static string GetUncPath (strin

下面是我获取通用路径的函数。我在这个主题上发现了各种相互冲突的帖子,这已经经过了多次迭代,但是这个函数通常是有效的。但是,大约有5%的时间它会导致应用程序崩溃。错误消息表明它可能已损坏内存。我找不到理由。在调试器下运行c#应用程序时,问题永远不会发生,但是如果我在错误发生后附加到进程,那么我可以查看WNetGetUniversalName返回的数据,它看起来与没有崩溃时完全相同。我想知道是什么原因造成的

        public static string GetUncPath (string localPath)
    {
        if (localPath.IndexOf ('\\')== 0)
            return localPath;               // already a unc path

        int bufferSize = 8000;
        IntPtr buffer = Marshal.AllocHGlobal (bufferSize);

        int ret = WNetGetUniversalName (localPath, UNIVERSAL_NAME_INFO_LEVEL, buffer, ref bufferSize);

        if (ret == 2250)
            return localPath;

        string result = "";
        if (ret == 0) {
            IntPtr ptr = Marshal.ReadIntPtr (buffer);
            result = Marshal.PtrToStringAuto (ptr, bufferSize);
            result = result.Substring (0, result.IndexOf ('\0'));
        }
        Marshal.FreeHGlobal (buffer);
        return result;
    }

    [DllImport ("mpr.dll", EntryPoint="WNetGetUniversalName", 
       CharSet=CharSet.Unicode, SetLastError=false)]
    [return: MarshalAs (UnmanagedType.U4)]
    static extern int WNetGetUniversalName (string lpLocalPath,
        [MarshalAs (UnmanagedType.U4)] int dwInfoLevel,
        IntPtr lpBuffer,
        [MarshalAs (UnmanagedType.U4)] ref int lpBufferSize);
崩溃总是发生在对Marshal.PtrToStringAuto的调用中。同样,当崩溃发生时,缓冲区中的数据看起来绝对正确

请注意,我已经设置了8000字节的缓冲区。我从2000开始,认为这足够了,因为返回的字符串都少于200字节。但使用8000似乎可以减少崩溃。这有点主观,因为崩溃是完全随机的,有时长时间不发生,而有时几乎每次应用程序启动时都会发生

这是一个64位应用程序。这些错误发生在Windows 7 Pro和Windows 10上

有什么想法吗? 谢谢,罗斯

好的,多亏了本,我得到了答案。这是我最后的工作代码:

public static string GetUncPath (string localPath)
{
    if (localPath.IndexOf ('\\')== 0)
        return localPath;               // already a unc path

    int bufferSize = 512;
    IntPtr buffer = Marshal.AllocCoTaskMem (bufferSize);
    int ret = WNetGetUniversalName (localPath, UNIVERSAL_NAME_INFO_LEVEL, 
              buffer, ref bufferSize);

    if (ret == 2250) {            // if localpath is on the local computer
        Marshal.FreeCoTaskMem (buffer);
        return localPath;
    }

    string result = "";
    if (ret == 0) {
        IntPtr ptr = Marshal.ReadIntPtr (buffer);
        result = Marshal.PtrToStringAuto (ptr);
    }
    Marshal.FreeCoTaskMem (buffer);
    return result;
}

以下行中有三个错误:

result = Marshal.PtrToStringAuto (ptr, bufferSize);
@tolanj在评论中指出,返回时
bufferSize
是写入的字节总数,包括
\u UNIVERSAL\u NAME\u INFOW
结构本身的大小。不是字符串中的字节数

第二个参数是
Marshal.PtrToStringAuto
,它的第二个参数是要从指定指针读取的字符数,但传递的是字节数

第三,您使用
CharSet.Unicode
导入了函数,因此您知道您总是会得到
WNetGetUniversalNameW
\u UNIVERSAL\u NAME\u INFOW
和UTF-16字符串数据。因此,您应该使用
PtrToStringUni
not
PtrToStringAuto
1。上述两个问题也适用于
PtrToStringUni


PtrToStringAuto
行为记录为

在Unicode平台上,此方法调用
PtrToStringUni
;在ANSI平台上,它调用
PtrToStringAnsi
。在调用这些方法之前不进行任何转换


有时候你不想要一个,有时候你不想要另一个。p/invoke声明正在所有平台上强制使用Unicode。

我注意到您没有处理缓冲区不够长并且返回错误数据的情况。在这里查看一个修复它的实现:问题与字符串中的编码类型有关。PtrToStringAuto试图自动检测字符串中的编码。字符串是否更改(UTF-8和/或Unicode)?。如果字符串始终为8位,则使用UTF-8(LpStr)。请参阅:除了检查错误\u更多\u数据外,我从文档中了解到,缓冲区中填充的是通用\u名称\u信息(IntPtr size),然后是实际字符,而bufferSize将是这些大小的总和(写入缓冲区的实际数量),因此,您似乎应该将小于bufferSize的字节拉入Marshal.PtrToStringAuto。我会尝试Marshal.PtrToStringAuto的重载,它不会占用较长的时间,这不是问题的原因,但会丢失
Marshal.AllocHGlobal
Marshal.FreeHGlobal
,只是暂时固定一个普通的C#数组。手动内存管理总是乱七八糟的,手动内存管理与函数名不符的情况几乎是一样糟糕。@jdweng:“
PtrToStringAuto
试图自动检测字符串中的编码”与文档相矛盾。你从哪里得到这个主意的?