c# - 为什么 FindMimeFromData 可以识别一台主机上的图像/tiff,但不能识别另一台主机上的图像/tiff?

标签 c# winapi mime-types mime urlmon

我正在使用 urlmon.dll 中的 FindMimeFromData 来嗅探上传文件的 MIME 类型。根据MIME Type Detection in Internet Explorer , 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);
    // ...
}

最佳答案

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

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

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.

TIFF Compression Tag部分清楚地显示了许多罕见的压缩方案,正如我怀疑的那样,在早期版本的 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 副本可能违反 Microsoft 的政策
  • 编码:你必须加载the dll dynamically调用 FindMimeFromData 函数或至少自定义应用程序的 list 文件,因为 Dynamic-Link Library Search Order .我假设您知道,手动将较新版本的 urlmon.dll 复制到系统文件夹是一个非常糟糕的主意,因为其他应用程序很可能会在使用它时崩溃。

无论如何,祝你好运解决你的 urlmon 谜语。

关于c# - 为什么 FindMimeFromData 可以识别一台主机上的图像/tiff,但不能识别另一台主机上的图像/tiff?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6622015/

相关文章:

c# - 在多维数组上运行 SQL 的最快方法

c# - DataflowBlock ITargetSource.AsObservable() 不触发 OnNext()

c# - 在 C#.NET 中设置 NTFS 权限

c# - 工作 C# 示例 : Writing & Reading NTFS Alternate Data Stream Under Win7 64 bit

c++ - 解除分配不会释放 Windows/C++ 应用程序中的内存

java - 获取文件的 MIME 类型

iis-7.5 - IIS 7 中没有 Mime 类型选项

c# - SQL事务失败

c - select 未检测到本地主机连接已关闭

python - 确定 MIME 类型是二进制的还是基于文本的