Windows is a powerful platform, at least, if you know which APIs are at your service :)

For instance, function FindMimeFromData (exported from UrlMon.dll) was very helpfull in telling me that the user is opening the right type of file based on the content-type. I did not test if this is full proof for all conten types, but I just needed it for determing the type of image (jpeg/png/gif/wmf/emf/tif/ etc) and that works! You can't fool this function, by modifying the extension of the file, from .jpg to .gif for instance!

I got this TIP from a hardcore ATL programmer Alex Fedotov. The Russians are the best programmers :). And in fact, you could easily use this function in C# as well.

Spasiba! (it seems that .Text developers did not utilize nvarchar (unicode-16) for text its database storage so I can't use russian characters)

ps: If you wonder if I copied this from pinvoke.net, no, it's the other way around :)

 

[DllImport("urlmon.dll", EntryPoint="FindMimeFromData", 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,

    [MarshalAs(UnmanagedType.LPWStr)]

      out string ppwzMimeOut,

      int dwReserved);

 

/// <summary>

/// Ensures that file exists and retrieves the content type

/// </summary>

/// <param name="file"></param>

/// <returns>Returns for instance "images/jpeg" </returns>

public static string getMimeFromFile(string file)

{

 

    if (!System.IO.File.Exists(file))

        throw new FileNotFoundException(file + " not found");

 

    int MaxContent = (int)new FileInfo(file).Length;

    if (MaxContent > 4096) MaxContent = 4096;

 

    FileStream fs = File.OpenRead(file);

 

    byte[] buf = new byte[MaxContent];

    fs.Read(buf, 0, MaxContent);

    fs.Close();

 

    string mime;

    //note: the CLR frees the data automatically returned in ppwzMimeOut     

    int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, out mime, 0);

 

    if (result != 0)           

       throw Marshal.GetExceptionForHR(result);

 

   return mime;

}


Note that the MSDN does not tell us, how to free the returned data pointed by ppwzMimeOut. I simply assume it to be a CoTaskAlloc-ed string and if it were not true, we have no problem unless you try to run this on a winblows 9.x environment. If someone knows facts about this please let me know.

Here it comes in C++.

///<summary>
/// accepts an existing path to a file and reads some bytes (max 4096) to determine the content type
///</summary>
///
<returns>"images/jpeg" for instance</returns>

STDMETHODIMP GetContentType(PCWSTR file, BSTR* contentType) throw()

{    

      AtlTrace(L"GetContentType %s\n", file);

 

      CAtlFile fl;

      ULONGLONG maxContent ;

 

      HRESULT hr = fl.Create(file, FILE_READ_DATA, FILE_SHARE_READ, OPEN_EXISTING);

      if (hr != S_OK) return hr;

 

      hr = fl.GetSize(maxContent);

      DWORD maxData = maxContent > 4096 ? 4096 : (DWORD)maxContent;

     

      CTempBuffer<BYTE, 4096, CComAllocator> data(maxData);

      PWSTR mime;

 

      if (data != NULL)

      {

            hr = fl.Read(data, maxData, maxData);

            fl.Close();

            // have urlmon do the task   

            hr = FindMimeFromData(NULL, file, data, maxData, NULL, 0, &mime, 0);           

      }

      else

            return E_OUTOFMEMORY;

 

      if (SUCCEEDED(hr)) 

      {
         
*contentType = CComBSTR(mime).Detach();

         CoTaskMemFree(mime);

      }

      

      return hr;

}