2

Is there any way to can get the MIME Type in C++ given a file extension?

I have read about HKEY_CLASSES_ROOT, but I honestly have no idea of how to use it.

What I want is having as input:

 string extension=".pdf"; 
 string extension2=".avi";

Get as output:

string mimeType="application/pdf";
string mimeType2="video/x-msvideo";

I know I could do this by myself, but I guess there is some work already done in here.

Thanks a lot

user3009804
  • 329
  • 6
  • 19

2 Answers2

8

The simplest solution involves calling FindMimeFromData:

#include <urlmon.h>
#pragma comment( lib, "urlmon" )

std::wstring MimeTypeFromString( const std::wstring& str ) {

    LPWSTR pwzMimeOut = NULL;
    HRESULT hr = FindMimeFromData( NULL, str.c_str(), NULL, 0,
                                   NULL, FMFD_URLASFILENAME, &pwzMimeOut, 0x0 );
    if ( SUCCEEDED( hr ) ) {
        std::wstring strResult( pwzMimeOut );
        // Despite the documentation stating to call operator delete, the
        // returned string must be cleaned up using CoTaskMemFree
        CoTaskMemFree( pwzMimeOut );
        return strResult;
    }

    return L"";
}

The following application

int _tmain( int argc, _TCHAR* argv[] ) {
    std::wcout << L".pdf: " << MimeTypeFromString( L".pdf" ) << std::endl;
    std::wcout << L".avi: " << MimeTypeFromString( L".avi" ) << std::endl;

    return 0;
}

produces this output on my system:

.pdf: application/pdf
.avi: video/avi
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • thanks a lot for your code! I have tried it using several extensions and in some of them works and in some doesn't, for example .avi (yes, don't get how can't work .avi), .mov, .mp3, .mp4, .mpeg, .vmw, ... do you know what can be happening? thanks a lot! – user3009804 Dec 18 '13 at 10:24
  • From some tests I've made in a tight loop (a `while (true) {})` while looking with the Task Manager) I concur with `CoTaskMemFree`. – xanatos Jun 26 '18 at 08:32
6

As it's nearly Christmas, How about this:

#include <Windows.h>
#include <string>

using namespace std;

string GetMimeType(const string &szExtension)
{
    // return mime type for extension
    HKEY hKey = NULL;
    string szResult = "application/unknown";

    // open registry key
    if (RegOpenKeyEx(HKEY_CLASSES_ROOT, szExtension.c_str(), 
                       0, KEY_READ, &hKey) == ERROR_SUCCESS)
    {
        // define buffer
        char szBuffer[256] = {0};
        DWORD dwBuffSize = sizeof(szBuffer);

        // get content type
        if (RegQueryValueEx(hKey, "Content Type", NULL, NULL, 
                       (LPBYTE)szBuffer, &dwBuffSize) == ERROR_SUCCESS)
        {
            // success
            szResult = szBuffer;
        }

        // close key
        RegCloseKey(hKey);
    }

    // return result
    return szResult;
}

int main(int argc, char* argv[])
{
    string szExt1 = ".pdf";
    string szExt2 = ".avi";

    string szMime1 = GetMimeType(szExt1);
    string szMime2 = GetMimeType(szExt2);

    printf("%s = %s\n%s = %s\n", szExt1.c_str(), szMime1.c_str(), 
        szExt2.c_str(), szMime2.c_str());

    return 0;
}

On my system, it gives the following output:

.pdf = application/pdf
.avi = video/avi

Roger Rowland
  • 25,885
  • 11
  • 72
  • 113
  • thanks for your time Roger, I am getting unexpected outputs but will check this deeper ;) – user3009804 Dec 17 '13 at 15:52
  • 1
    @user3009804 Ok - just let me know if I can help further (while I'm still feeling Christmassy). As you'd used `string` in your question, I made a non-UNICODE example. – Roger Rowland Dec 17 '13 at 15:53
  • Good afternoon Roger, I have tried out your non-UNICODE code as well as IInspectable's code and I have found out that with your code I am able to get some extension's MIME TYPE but I can't with other extensions. For example I get that the application is unknown with extensions such as: .avi, .mp3. .mp4, .wmv, .rar, .log, .... Do you know what can be wrong? Thanks for all ;) – user3009804 Dec 18 '13 at 14:55
  • 1
    @user3009804 - Well it's just reading the registry so take a look with Regedit.exe at, for example, `HKEY_CLASSES_ROOT\.mp3` and see if there is a `Content Type` key. If there is, it may be a permissions issue. There is also a reverse look-up at `HKEY_CLASSES_ROOT\MIME\Database\Content Type`. – Roger Rowland Dec 18 '13 at 15:11
  • @user3009804 you know it might be worth combining my approach with IInspectable's - as I understand it, his will only give the 26 (or so) predefined types, while mine will only give those where the extension is registered with an application. If one fails, the other may succeed. – Roger Rowland Dec 18 '13 at 15:29
  • damm.... I get that error cause in Regedit.exe in the HKEY_CLASSES_ROOT\.mp3 I have no content type... whole day thrown to the rubbisth thanks WIndows xD. Thanks a lot Roger for all your help :) – user3009804 Dec 18 '13 at 15:56
  • @RogerRowland I don't believe that is the case--@IInspectable's answer will fall back on the registry if the file type is not one of the 26. For example, in my tests it handles .py, .pyz, and .ogg files correctly on win10. See step #4 in https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms775147%28v%3dvs.85%29#mime-type-detection-algorithm That being said, your approach avoids linking with any external libraries, which I could foresee being useful in some circumstances. – Colin Atkinson Jul 09 '19 at 22:56