为什么FindMimeFromData在一台主机上识别image / tiff,但在另一台主机上却没有?

时间:2011-07-08 08:42:35

标签: c# winapi mime-types mime urlmon

我正在使用FindMimeFromData中的urlmon.dll来嗅探上传文件的MIME类型。根据{{​​3}},image/tiff是公认的MIME类型之一。它在我的开发机器(Windows 7 64位,IE9)上工作正常,但在测试环境(Windows Server 2003 R2 64位,IE8)上不起作用 - 它返回application/octet-stream而不是image/tiff。< / p>

上面的文章描述了确定MIME类型所采取的确切步骤,但由于image/tiff是26种已识别类型之一,因此它应该在第2步结束(嗅探实际数据),以便文件扩展名和注册申请(和其他注册表内容)无关紧要。

哦,顺便说一下,TIFF文件实际上 与测试服务器上的程序(Windows图片和传真查看器)相关联。并不是Windows注册表中没有任何对TIFF的引用。

为什么它没有按预期工作的任何想法?

编辑: FindMimeFromData使用如下:

public class MimeUtil
{
    [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
    private 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);

    public static string GetMimeFromData(byte[] data)
    {
        IntPtr mimetype = IntPtr.Zero;
        try
        {
            const int flags = 0x20; // FMFD_RETURNUPDATEDIMGMIMES
            int res = FindMimeFromData(IntPtr.Zero, null, data, data.Length, null, flags, out mimetype, 0);
            switch (res)
            {
                case 0:
                    string mime = Marshal.PtrToStringUni(mimetype);
                    return mime;
                // snip - error handling
                // ...
                default:
                    throw new Exception("Unexpected HRESULT " + res + " returned by FindMimeFromData (in urlmon.dll)");
            }
        }
        finally
        {
            if (mimetype != IntPtr.Zero)
                Marshal.FreeCoTaskMem(mimetype);
        }
    }
}

然后像这样调用:

protected void uploader_FileUploaded(object sender, FileUploadedEventArgs e)
{
    int bsize = Math.Min(e.File.ContentLength, 256);
    byte[] buffer = new byte[bsize];
    int nbytes = e.File.InputStream.Read(buffer, 0, bsize);
    if (nbytes > 0)
        string mime = MimeUtil.GetMimeFromData(buffer);
    // ...
}

1 个答案:

答案 0 :(得分:5)

我无法重现您的问题,但我对该主题进行了一些研究。我相信它是您怀疑的,问题出在MIME类型检测的第2步:urlmon.dll v9中的硬编码测试与urlmon.dll v8中的测试不同。

关于TIFF的维基百科文章显示格式有多复杂,从一开始就存在问题:

  

引入TIFF时,其可扩展性会引发兼容性问题。编码的灵活性引发了一个笑话,即TIFF代表数千种不兼容的文件格式

TIFF Compression Tag部分清楚地显示了许多罕见的压缩方案,正如我怀疑的那样,在早期版本的IE中创建urlmon.dll硬编码测试时已被省略。

那么,可以做些什么来解决这个问题呢?我可以想到三个解决方案,但是每个解决方案都带来了不同类型的新问题:

  1. 将您的开发计算机上的IE更新为版本9.
  2. 在您的开发计算机上应用最新的IE 8更新。众所周知,经常引入urlmon.dll的修改版本(例如KB974455)。其中一个可能包含更新的MIME硬编码测试。
  3. 使用您的应用程序分发自己的urlmon.dll副本。
  4. 似乎解决方案1和2是您应该选择的解决方案。但是,生产环境可能存在问题。正如我的经验表明,生产环境的管理员经常不同意安装一些更新,原因有很多。可能更难说服管理员将IE更新为v9并更容易安装IE8 KB更新(因为他们应该这样做,但我们都知道它是怎么回事)。如果你控制了生产环境,我认为你应该选择解决方案1。

    第三种解决方案引入了两个问题:

    • legal:可能违反Microsoft的政策,分发自己的urlmon.dll副本
    • 编码:由于the dll dynamically,您必须加载Dynamic-Link Library Search Order来调用FindMimeFromData函数或至少自定义应用的清单文件。我假设你知道,将一个较新版本的urlmon.dll手动复制到系统文件夹是一个非常糟糕的主意,因为其他应用很可能会崩溃使用它。

    无论如何,祝你解决你的urlmon之谜。