c++windowswinapiaudiomci

mciSendString won't play an audio file if path is too long


When the path+filename of a file is really long, I've noticed that

PlaySound(fName.c_str(), NULL, SND_ASYNC);

works, but not

mciSendString((L"open \"" + fName + L"\" type waveaudio alias sample").c_str(), NULL, 0, NULL);
mciSendString(L"play sample", NULL, 0, NULL);

Example of failing command:

open "C:\qisdjqldlkjsqdjqdqjslkdjqlksjlkdjqsldjlqjsdjqdksq\dajdjqjdlqjdlkjazejoizajoijoifjoifjdsfjsfszjfoijdsjfoijdsoifoidsjfojdsofjdsoijfoisjfoijoisdjfosjfqsd\Windows Critical Stop.wav" type waveaudio alias sample

But:

How to make mciSendString accept long filenames?


Notes:


Solution

  • The 127 limit looks strange. I didn't find any information on MSDN about it.

    1. There is an alternative syntax to open: open waveaudio!right.wav

    2. An option You could try is to change the working directory to the directory of the file, then the limit only applies to filename. -> SetCurrentDiectory

    3. To shorten the filename a Winapi function can be used GetShortPathName
      But:

      SMB 3.0 does not support short names on shares with continuous availability capability.

      Resilient File System (ReFS) doesn't support short names. If you call GetShortPathName on a path that doesn't have any short names on-disk, the call will succeed, but will return the long-name path instead. This outcome is also possible with NTFS volumes because there's no guarantee that a short name will exist for a given long name.

    Based on example from MSDN:

    #include <string>
    #include <Windows.h>
    
    template<typename StringType>
    std::pair<bool, StringType> shortPathName( const StringType& longPathName )
    {
        // First obtain the size needed by passing NULL and 0.
        long length = GetShortPathName( longPathName.c_str(), NULL, 0 );
        if (length == 0) return std::make_pair( false, StringType() );
    
        // Dynamically allocate the correct size 
        // (terminating null char was included in length)
        StringType  shortName( length, ' ' );
    
        // Now simply call again using same long path.
        length = GetShortPathName( longPathName.c_str(), &shortName[ 0 ], length );
        if (length == 0) return std::make_pair( false, StringType() );
    
        return std::make_pair(true, shortName);
    }
    
    
    #include <locale>
    #include <codecvt>
    
    #include <iostream>
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    
    //std::string narrow = converter.to_bytes( wide_utf16_source_string );
    //std::wstring wide = converter.from_bytes( narrow_utf8_source_string );
    
    int main( int argc, char** argv )
    {
        std::wstring myPath = converter.from_bytes( argv[0] );
    
        auto result = shortPathName( myPath );
        if (result.first)
            std::wcout << result.second ;
    
    
        return 0;
    }