PtrToStringUni在Windows 10中不起作用

时间:2018-06-26 07:40:39

标签: c# marshalling

因此,我一直使用urlmon.dll的帮助来获取This答案中建议的文件数据的MIME类型,并且在Windows 7中可以正常工作。

但是,在Windows 10上,尝试从mime指针创建字符串时,相同的代码会生成System.AccessViolationException

这是有问题的代码:

uint mimeType;
FindMimeFromData(0, null, data, 256, null, 0, out mimeType, 0);
var mimePointer = new IntPtr(mimeType);
//Exception is thrown on the next line
var mime = Marshal.PtrToStringUni(mimePointer);

该代码在Windows 7和相同文件上都能正常工作,但是在Windows 10上运行时,我突然遇到访问冲突。

还有其他人遇到此错误吗?

1 个答案:

答案 0 :(得分:3)

uint mimeType;
FindMimeFromData(0, null, data, 256, null, 0, out mimeType, 0);
var mimePointer = new IntPtr(mimeType);

这在64位上肯定是错误的... IntPtr是64位(它是一个内存地址)... uint(32位)如何包含它?

如果我们看看pinvoke site,签名应该是:

[DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
static extern int FindMimeFromData(IntPtr pBC,
    [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.I1, SizeParamIndex=3)] 
    byte[] pBuffer,
    int cbSize,
    [MarshalAs(UnmanagedType.LPWStr)] string pwzMimeProposed,
    int dwMimeFlags,
    out IntPtr ppwzMimeOut,
    int dwReserved);

非常重要,尽管该方法的文档在msdn上非常贫乏,但调用FindMimeFromData会导致内存泄漏:您必须释放收到的ppwzMimeOut。问题是不清楚如何:建议here使用CoTaskMemFree,即Marshal.FreeCoTaskMem。我会说这是正确的,并经过以下测试:

byte[] bytes = File.ReadAllBytes("someimage.jpg");

while (true)
{
    IntPtr ptr1;
    int success1 = FindMimeFromData(IntPtr.Zero, null, bytes, bytes.Length, null, 0, out ptr1, 0);
    Marshal.FreeCoTaskMem(ptr1);
}

如果我删除Marshal.FreeCoTaskMem并查看TaskManager,则该进程使用的内存将很快增加...如果我恢复Marshal.FreeCoTaskMem,则内存将保持稳定。