当文件的路径+文件名很长时,我注意到了
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);
命令失败的示例:
打开" C:\ qisdjqldlkjsqdjqdqjslkdjqlksjlkdjqsldjlqjsdjqdksq \ dajdjqjdlqjdlkjazejoizajoijoifjoifjdsfjsfszjfoijdsjfoijdsoifoidsjfojdsofjdsoijfoisjfoijoisdjfosjfqsd \ Windows Critical Stop.wav"输入waveaudio别名样本
可是:
我真的需要mciSendString而不是PlaySound(),因为PlaySound()不播放某些文件(48 khz音频文件,有时是24位文件等)
我需要能够播放具有潜在长路径的音频文件,因为我的应用的最终用户可能有这样的文件
如何让mciSendString接受长文件名?
注意:
我也使用mciSendCommand尝试了这个MSDN示例,但它是一样的。
最大路径+文件名长度为127(127:工作,128 +:不工作)
如果真的,mci*
函数无法使用长于127个字符的文件名,那么我可以使用winapi(没有外部库)? (PlaySound
不是一个选项,因为它不能与所有wav文件一起使用,例如48 khz:non-working等。)
答案 0 :(得分:4)
127限制看起来很奇怪。我没有在MSDN上找到任何关于它的信息。
可以打开另一种语法:open waveaudio!right.wav
您可以尝试的选项是将工作目录更改为文件目录,然后限制仅适用于filename。 - > 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;
}
答案 1 :(得分:2)
这是传统MCI功能的限制。使用MCI API时会遇到两个问题:
路径名为too long,此API无法处理长文件名。如页面所示,限制通常约为260
个字符。
并非所有文件都有&#34;短名称&#34;。 Starting with Windows 7,可以禁用所谓的8.3
(FILENAME.EXT
)文件创建。这意味着可能没有GetShortPathName
可以返回的路径允许MCI访问该文件。
强烈建议使用现代API替换整个内容。其他评论者提到的DirectDraw
和Media Foundation
将是合适的替代品。
答案 2 :(得分:2)
我调试了它(在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
此处,使用MMIO_PARSE
标志调用mmioOpen
以将文件路径转换为完全限定的文件路径。根据MSDN,这有一个限制:
缓冲区必须足够大才能容纳至少128个字符。
也就是说,缓冲区总是假定为128字节长。对于长文件名,缓冲区结果不足,mmioOpen
返回错误,导致mciSendCommand
认为声音文件丢失并返回MCIERR_FILENAME_REQUIRED
。
不幸的是,由于它正在解析完全限定的文件路径,SetCurrentDirectory
无济于事。
由于问题出在MCI驱动程序(mciwave.dll
)内,我怀疑是否有办法迫使MCI子系统处理长路径。
答案 3 :(得分:0)
考虑到你的限制(无法改变任何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
}
您可以使用result
上的mciGetErrorString来查找您正在获取的确切错误代码,并使if
具体,或者以不同的方式处理其他错误。我看了在the list of errors,但我不确定。
如果您创建了新文件,请不要忘记使用Windows API中的DeleteFile
。我不知道你是想在节目结束之前还是在比赛结束后立即保留它,所以决定什么更有意义。
如果出现其他问题,您还需要检查CopyFile
是否成功。你真的需要在这里到处检查自己。