urlmon.dll FindMimeFromData() works perfectly on 64bit desktop/console but generates errors on ASP.NET

T-moty picture T-moty · Aug 21, 2013 · Viewed 7.7k times · Source

I am creating a library of utilities to be used both in desktop environment in a web environment.

It contains several features that I believe are often repeated in my applications, including utility to get the mime type of a file by its content (not the extension).

The files that I'll have to check are the most common (jpg, png, pdf, txt) so I chose to use the external method FindMimeFromData (link above)

Using .NET, how can you find the mime type of a file based on the file signature not the extension

The method works well, except for the two incorrect mime type of JPG (image/pjpg) and PNG (image/x-png), easily solved by doing a check before the return statement.

The library is compiled for the platform AnyCPU, because it must be installed on servers/clients in both 32 and 64 bits.

At the time of testing on desktop environment all working properly for both applications compiled for x86 and x64.

at the time of testing an ASP.NET application (an empty site with an http handler for test) occurs an error of type HRESULT, and the debugger tells me that it can not provide further information.

After a few test configuration, including changing the identity of the pool to Local System (with no result), I have identified the problem:

the pool should allow 32-bit applications (see image above).

IisAllow32BitApplication

Why?

It should not load the dll urlmon.dll of the 64bit system where we are now?

This is a big problem, because the FindMimeFromData method can be invoked by everywhere into this library:

the result is that an invocation of this method by another utility method may throw this exception and making it difficult to trace the problem also through debugging.

Any ideas/experience ?

Operating Systems used for testing

Desktop:

  1. Windows 8 x64 - works
  2. Windows 7 x64 - works
  3. Windows Server 2008 Standard R2 x64 - works
  4. Windows Server 2008 Standard x86 - works
  5. Windows Server 2003 Standard x86 - works
  6. Windows XP Professional SP3 - works

Web:

  1. Windows 8 x64 - first error found, works only with 32bit application enabled
  2. Windows Server 2008 Standard R2 x64 - error confirmed, works only with 32bit application enabled
  3. Windows Server 2008 Standard x86 - works

EDIT 2 (question solved)

Solved by Noseratio:

The correct type of parameters ppwzMimeOut and pBC must be System.IntPtr instead of System.UInt32.

I know that System.UInt32 causes problems into full 64bit web-apps, but i don't know why.

If someone know the reason of these problems, can explain it better in a comment?

Thanks in advance

Answer

noseratio picture noseratio · Sep 1, 2013

If you used the pinvoke signature from the answer your linked, it's defined there like this:

[DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
private extern static System.UInt32 FindMimeFromData(
    System.UInt32 pBC,
    [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl,
    [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
    System.UInt32 cbSize,
    [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed,
    System.UInt32 dwMimeFlags,
    out System.UInt32 ppwzMimeOut,
    System.UInt32 dwReserverd
);

I would rather use the defintion from pinvoke.net:

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

Note the difference in types for ppwzMimeOut and pBC parameter. In the former case, System.UInt32 is not a correct type for a 64-bit pointer under a 64-bit platform. For pBC, this is probably not an issue (as long as it is NULL), but it matters for ppwzMimeOut.

Refer to this implementation which appears to be correct.