Когда путь + имя файла действительно длинный, я заметил, что
PlaySound(fName.c_str(), NULL, SND_ASYNC);
работает, но не
mciSendString((L"open \"" + fName + L"\" type waveaudio alias sample").c_str(), NULL, 0, NULL);
mciSendString(L"play sample", NULL, 0, NULL);
Пример неудачной команды:
open «C: \ qisdjqldlkjsqdjqdqjslkdjqlksjlkdjqsldjlqjsdjqdksq \ dajdjqjdlqjdlkjazejoizajoijoifjoifjifsfjsfszjfoijdsjfoijsjof
Но:
Мне действительно нужно mciSendString вместо PlaySound (), потому что PlaySound () не воспроизводит определенные файлы (аудиофайлы 48 кГц, иногда 24-битные файлы и т. Д.)
Мне нужно иметь возможность воспроизводить аудиофайлы с потенциально длинными путями, потому что конечные пользователи моего приложения могут иметь такие файлы
Как заставить mciSendString принимать длинные имена файлов?
Заметки:
Я также пытался с этим примером MSDN, используя mciSendCommand, но это то же самое.
Максимальный путь + длина имени файла — 127 (127: работает, 128+: не работает)
Если действительно невозможно сделать mci*
функции работают с именами файлов длиной более 127 символов, что я могу использовать вместо них, только с winapi (без внешних библиотек)? (PlaySound
это не вариант, потому что не работает достоверно со всеми файлами WAV, такими как 48 кГц: нерабочий и т. д.)
Предел 127 выглядит странно. Я не нашел никакой информации на MSDN об этом.
Существует альтернативный синтаксис для открытия: open waveaudio!right.wav
Вариант, который вы можете попробовать, это изменить рабочий каталог на каталог файла, тогда ограничение будет применяться только к имени файла. -> SetCurrentDiectory
Чтобы сократить имя файла, можно использовать функцию Winapi GetShortPathName
Но:
SMB 3.0 не поддерживает короткие имена на акциях с непрерывным
Возможность доступности.Эластичная файловая система (ReFS) не поддерживает короткие имена. Если вы позвоните
GetShortPathName для пути, который не имеет коротких имен на диске,
вызов будет успешным, но вместо этого вернется путь с длинным именем.
Этот результат также возможен с томами NTFS, потому что нет
гарантировать, что короткое имя будет существовать для данного длинного имени.
На основе примера из 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;
}
Это ограничение унаследованных возможностей MCI. Есть две проблемы, с которыми вы сталкиваетесь при использовании MCI API:
Имя пути слишком долго, и этот API не может обрабатывать длинные имена файлов. Ограничение, как правило, вокруг 260
символы, как указано на странице.
Не все файлы имеют «короткое имя». Начиная с Windows 7, так называемый 8.3
(FILENAME.EXT
) создание файла может быть отключено. Это означает, что не может быть пути, который GetShortPathName
может вернуть, что позволит MCI получить доступ к файлу.
Настоятельно рекомендуется заменить все это современным API. DirectDraw
а также Media Foundation
Как уже упоминалось другими комментаторами, будут подходящие замены.
Я отладил это (на mciSendCommand
пример). Проблема возникает, когда mwOpenDevice
звонки mmioOpen
:
winmm.dll!_mciSendCommandW@16
winmm.dll!mciSendCommandInternal
winmm.dll!mciSendSingleCommand
winmm.dll!_mciOpenDevice@12
winmm.dll!mciLoadDevice
winmm.dll!_mciSendCommandW@16
winmm.dll!mciSendCommandInternal
winmm.dll!mciSendSingleCommand
winmmbase.dll!_DrvSendMessage@16
winmmbase.dll!InternalBroadcastDriverMessage
mciwave.dll!_DriverProc@20
mciwave.dll!_mciDriverEntry@16
mciwave.dll!_mwOpenDevice@12
winmmbase.dll!_mmioOpenW@12
Вот, mmioOpen
называется с MMIO_PARSE
флаг для преобразования пути к файлу в полный путь к файлу. Согласно MSDN, это имеет ограничение:
Буфер должен быть достаточно большим, чтобы содержать не менее 128 символов.
То есть буфер всегда имеет длину 128 байт. Для длинных имен файлов буфер оказывается недостаточным и mmioOpen
возвращает ошибку, вызывающую mciSendCommand
думать, что звуковой файл отсутствует и вернуться MCIERR_FILENAME_REQUIRED
,
К сожалению, поскольку он разрешает полный путь к файлу, SetCurrentDirectory
не поможет
Так как проблема внутри драйвера MCI (mciwave.dll
Я сомневаюсь, что есть способ заставить подсистему MCI обрабатывать длинный путь.
Учитывая ваши ограничения (не могут изменить API), которые являются предметом MCI, я бы рассмотрел копирование запрашиваемого в данный момент файла в temp
и играть там, в случае неудачи с первой попытки:
int result = mciSendString(...);
if (result > 0 ) { #See notes below to specify this
CopyFile("C:\\long\\path.wav","C:\\temp\\play.wav",0); #windows.h
result = mciSendString(...); #In c:/temp/play.wav
}
Ты можешь использовать mciGetErrorString на result
найти точный код ошибки, который вы получаете — и сделать if
конкретные, возможно, обрабатывать другие ошибки по-другому .. Я смотрел на список ошибок но я не уверен
Не забудьте использовать DeleteFile
из Windows API, если вы создали новый файл. Я не знаю, хотите ли вы сохранить его до окончания программы или сразу после игры, поэтому решите, что имеет больше смысла.
Вы также хотите проверить на успех CopyFile
на случай, если что-то пойдет не так. Вы действительно должны проверить себя везде здесь.