PtrToStringUni在Windows 10中不起作用

问题描述:

所以我一直在使用 urlmon.dll 的帮助来获取文件的MIME类型,如

So i have been using urlmon.dll's help with getting the MIME type of files' data as suggested in This answer, and its been working fine in windows 7.

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

However, on windows 10 the same code generates System.AccessViolationException when trying to create a string from the mime pointer.

这是有问题的代码:

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上运行时,我突然遇到访问冲突.

The code works fine on windows 7 and on the same files, however when running this on windows 10 i suddenly get Access Violation.

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

Did anyone else encounter this error ?

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

这肯定是错误的64位... IntPtr 是64位(它是一个内存地址)... uint (32位怎么可能))包含它?

This is surely wrong at 64 bits... A IntPtr is 64 bits (it is a memory address)... How could a uint (a 32 bits) contain it?

如果我们看一下 pinvoke网站,签名应该是:

And if we take a look at the pinvoke site the signature should be:

[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 代码>您收到...问题是,尚不清楚如何:此处建议使用 CoTaskMemFree ,即 Marshal.FreeCoTaskMem .我会说这是正确的,并通过以下方式进行了测试:

very important while the documentation of the method is very poor on msdn, calling FindMimeFromData will cause a memory leak: you have to free the ppwzMimeOut you receive... The problem is that it isn't clear how: here it is suggested to use CoTaskMemFree, that is Marshal.FreeCoTaskMem. I'll say that it is right, tested with:

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 ,内存将保持稳定.

If I remove the Marshal.FreeCoTaskMem and take a look with the TaskManager, the memory used by the process will go up quite quickly... If I restore the Marshal.FreeCoTaskMem, the memory will remain stable.