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

发布于 2024-11-18 23:04:57 字数 2483 浏览 6 评论 0原文

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

上面的文章描述了确定 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);
    // ...
}

I'm using FindMimeFromData from urlmon.dll for sniffing uploaded files' MIME type. According to MIME Type Detection in Internet Explorer, image/tiff is one of the recognized MIME types. It works fine on my development machine (Windows 7 64bit, IE9), but doesn't work on the test env (Windows Server 2003 R2 64bit, IE8) - it returns application/octet-stream instead of image/tiff.

The above article describes the exact steps taken to determine the MIME type, but since image/tiff is one of the 26 recognized types, it should end on step 2 (sniffing the actual data), so that file extensions and registered applications (and other registry stuff) shouldn't matter.

Oh and by the way, TIFF files actually are associated with a program (Windows Picture and Fax Viewer) on the test server. It's not that any reference to TIFF is absent in Windows registry.

Any ideas why it doesn't work as expected?

EDIT: FindMimeFromData is used like this:

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);
        }
    }
}

which is then called like this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

—━☆沉默づ 2024-11-25 23:04:57

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

维基百科关于 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 谜题。

I was unable to reproduce your problem, however I did some research on the subject. I believe that it is as you suspect, the problem is with step 2 of MIME Type Detection: the hard-coded tests in urlmon.dll v9 differ from those in urlmon.dll v8.

The Wikipedia article on TIFF shows how complex the format is and that is has been a problem from the very beginning:

When TIFF was introduced, its extensibility provoked compatibility problems. The flexibility in encoding gave rise to the joke that TIFF stands for Thousands of Incompatible File Formats.

The TIFF Compression Tag section clearly shows many rare compression schemes that, as I suspect, have been omitted while creating the urlmon.dll hard-coded tests in earlier versions of IE.

So, what can be done to solve this problem? I can think of three solutions, however each of them brings different kind of new problems along:

  1. Update the IE on your dev machine to version 9.
  2. Apply the latest IE 8 updates on your dev machine. It is well known that modified versions of urlmon.dll are introduced frequently (eg. KB974455). One of them may contain the updated MIME hard-coded tests.
  3. Distribute own copy of urlmon.dll with your application.

It seems that solutions 1 and 2 are the ones you should choose from. There may be a problem, however, with the production environment. As my experience shows the administrators of production env often disagree to install some updates for many reasons. It may be harder to convince an admin to update the IE to v9 and easier to install an IE8 KB update (as they are supposed to, but we all know how it is). If you're in control of the production env, I think you should go with solution 1.

The 3rd solution introduces two problems:

  • legal: It may be against the Microsoft's policies to distribute own copy of urlmon.dll
  • coding: you have to load the dll dynamically to call the FindMimeFromData function or at least customize your app's manifest file because of the Dynamic-Link Library Search Order. I assume you are aware, that it is a very bad idea just to manually copy a newer version of urlmon.dll to the system folder as other apps would most likely crash using it.

Anyway, good luck with solving your urlmon riddle.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文