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