开发者

Why does FindMimeFromData recognize image/tiff on one host, but doesn't on another one?

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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜