【问题标题】:PtrToStringUni doesnt work in windows 10PtrToStringUni 在 Windows 10 中不起作用
【发布时间】:2018-12-04 20:30:54
【问题描述】:

所以我一直在使用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 上运行时我突然遇到访问冲突。

有没有其他人遇到过这个错误?

【问题讨论】:

  • 您是否在管理模式下运行过它?还有您无法从文件扩展名中获取mimetype 的原因吗?
  • @AndrewE 是的,我尝试以管理员身份运行,但它不起作用(也不是解决方案,因为普通用户将在公司计算机上使用它,没有管理员权限)。我确实考虑了扩展名,但很多时候我使用的文件类型与扩展名不匹配(怪我们的客户),我更喜欢自己检查。
  • Windows 10 是 3 年前发布的,所以这不是“其他人是否遇到过这个”错误。它是目前唯一受支持的 Windows 版本。缓冲区可能太小,或者指针类型错误,或者您可能在 64 位机器上使用了 32 位版本的 DLL。至少,发布完整的异常,包括它的调用堆栈。您可以通过Exception.ToString() 轻松获取。
  • @Banana 试试看,你试过把Platform Target改成x64
  • @AndrewE 是的,我有,事实上这是我尝试的第一件事,但无济于事

标签: c# marshalling


【解决方案1】:
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,内存会保持稳定。

【讨论】:

  • 你的观点是有道理的,但它在 windows 7 64 位上运行得很好,在 windows 10 中有什么不同?
  • @Banana 并非所有 64 位地址都需要 64 位...有些地址低于 4gb,因此可转换为 32 位。但显然它是随机的
  • 正在测试它的计算机有 4gb 的内存,所以没有合格的地址会导致这个问题
  • @Banana 物理内存地址和虚拟内存地址是有区别的。您的 4GB 内存可以映射到任何地址。
  • @Banana 如果我必须做出有根据的猜测,我会说微软在 Windows 7 和 Windows 10 之间对ASLR(地址空间布局随机化)所做的更改导致内存分配超出4GB虚拟空间的“边界”。一种可能的随机化是关于自下而上的内存分配(请参阅here),我会说 that 是导致内存地址从“非常低”( 4gb)
猜你喜欢
  • 2016-03-08
  • 2015-12-12
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 2018-02-03
  • 1970-01-01
相关资源
最近更新 更多