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.