为什么FindMimeFromData在一台主机上识别image/tiff,而在另一台主机上却不能识别?

本文关键字:一台 主机 识别 不能 为什么 FindMimeFromData image tiff | 更新日期: 2023-09-27 18:01:36

我使用urlmon.dll中的FindMimeFromData来嗅探上传文件的MIME类型。根据Internet Explorer的MIME类型检测,image/tiff是可识别的MIME类型之一。它在我的开发机器(Windows 7 64位,IE9)上运行良好,但在测试环境(Windows Server 2003 R2 64位,IE8)上不起作用-它返回application/octet-stream而不是image/tiff

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

哦,顺便说一下,TIFF文件实际上与测试服务器上的一个程序(Windows Picture and Fax Viewer)相关联。这并不是说在Windows注册表中没有对TIFF的任何引用。

知道为什么它不像预期的那样工作吗?

EDIT: 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);
    // ...
}

为什么FindMimeFromData在一台主机上识别image/tiff,而在另一台主机上却不能识别?

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

维基百科关于TIFF的文章显示了TIFF格式是多么复杂,这从一开始就是一个问题:

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

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

那么,如何解决这个问题呢?我能想到三种解决方案,然而每一种都会带来不同类型的新问题:

  1. 在你的开发机器上更新IE到版本9
  2. 在开发机器上应用最新的IE 8更新。众所周知,urlmon.dll的修改版本经常被引入(例如。KB974455)。其中一个可能包含更新的MIME硬编码测试。
  3. 在应用程序中分发自己的urlmon.dll副本。

似乎解决方案1和2是你应该选择的。但是,生产环境可能存在问题。根据我的经验,生产环境的管理员经常出于多种原因不同意安装某些更新。说服管理员将IE更新到v9可能更难,而安装IE8 KB更新则更容易(正如他们应该做的那样,但我们都知道它是如何做到的)。如果生产环境由您控制,我认为您应该采用解决方案1。

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

  • 合法:分发自己的urlmon.dll拷贝可能违反微软的政策
  • 编码:你必须动态加载dll调用FindMimeFromData函数或至少自定义你的应用程序的清单文件,因为动态链接库搜索顺序。我想你已经意识到,这是一个非常糟糕的主意,只是手动复制一个新版本的urlmon.dll到系统文件夹,因为其他应用程序很可能会崩溃使用它。

无论如何,祝你好运解开你的谜语