Winamp 播放列表信息提示
用于快速预览音乐播放列表的信息提示外壳扩展

引言
有一些非常有用的实用程序可以扩展围绕 MP3 和其他媒体文件的 Shell 功能,例如 AudioShell。它们将媒体文件的元数据预览和编辑集成到 Windows Shell 本身,无需任何外部应用程序。最值得注意的 Shell 扩展示例是媒体文件元数据(如标题和艺术家信息)的预览。
本文遵循了相同的思路。本文介绍了一个 Shell 扩展,该扩展增加了对 PLS、M3U 和 M3U8 音乐播放列表的提示信息预览。PLS(由 Winamp 引入)和 M3U 是最广泛使用的播放列表格式,被 Winamp、Windows Media Player 和许多其他播放器支持。M3U 和 PLS 不支持 Unicode,而 M3U8 是一种 UTF8 扩展的 M3U 文件格式。
Vista Shell
XP 和 Vista 提示信息之间有一个关键区别。XP 中的提示信息字符数没有限制,而 Vista 对可显示字符数设置了限制。Vista 提示信息最多限制为约 900 个字符,即每行约 15 行,每行 65 个字符 + 第 16 行 5 个字符,如下图所示(来自生成长字符串以供提示信息的特殊测试)。

很难确定换行符 ('\n') 是否包含在计数中,但它们很可能被包含在内。
因此,播放列表解析和提示信息生成受到限制,以便在 Vista 和 XP 上都能正确显示提示信息。
我在这里没有包含 XP 上大型提示信息的屏幕截图,因为提示信息可以占用整个屏幕(如果足够大)。我不知道它会超出屏幕边界多少。
如果您系统中没有安装亚洲或其他宽字符语言文件,您可能会丢失一些字符,如果播放列表最初是用宽字符保存的(Vista 和 XP 屏幕截图)。
代码
此代码建立在 Dino Esposito 的优秀文章 Windows 2000 UI Innovations 的代码之上。强烈建议您先阅读它,因为它解释了许多我在这里不会涵盖的基本细节。有关 PLS 和 M3U/M3U8 格式,请参阅 Winamp 论坛上的 非官方规范。PLS 文件使用 Richard J. Wagner 的 ConfigFile 类 进行解析。
该项目使用 VC 2005 Express + Platform SDK2003 R2 + WTL 8.0 构建,并且很可能在 VC 2008 中无需任何更改即可构建。
主要的播放列表解析框架位于 PlaylistParser.cpp
中。播放列表格式由文件扩展名确定,并选择相应的解析函数。
PLAYLIST_TYPE C_PlaylistParser::getType(CString fpl)
{
fpl.MakeLower();
if (fpl.IsEmpty()) return NOTPLS;
if (fpl==_T("m3u")) return M3U;
if (fpl==_T("m3u8")) return M3U;
......
return NOTPLS;
}
int C_PlaylistParser::process(CString fpls)
{
playlistFile.Split(fpls);
playlistFile.ext_nodot.MakeLower();
try
{
playlistType=getType(playlistFile.ext_nodot);
switch (playlistType)
{
case M3U:
parseM3U();
break;
case PLS:
parsePLS();
break;
......
default:
break;
}
buildPlaylist();
}
catch (...) {return FALSE;}
return TRUE;
}
M3U 和 M3U8 都通过将文本行传递给 MultiByteToWideChar
并使用 CP_UTF8
标志来处理。
请注意,PLS 规范声明条目区分大小写。
buildPlaylist()
函数将存储在 vector 中的信息转换为具有以下布局的提示信息。
<track#>.<artist, title> <track playtime ##:##>
....
--------------------------------------------
Total playing time: ##:##:##
Size: ######
如果播放列表处理完全失败,将显示一个通用的提示信息(文件类型、大小)。
请注意,文件大小是通过 GetFileSize
确定的,该函数仅对小于 2GB 的文件有效。虽然这不是一个好习惯,但播放列表不太可能大于 2 GB。
最后,我们必须不要忘记在 CBmpTip::GetBitmapInfo
方法中使用 try/catch
块,以防止任何可能的错误导致 Explorer 崩溃(例如,在使用中拔出 USB 驱动器)。在源代码包中有一个小的测试项目(*PLS.sln*)用于测试解析器代码,因为在 Windows Explorer 中调试 Shell 扩展可能非常不方便。
对于某些媒体类型(如 *.ogg),播放列表可能会省略曲目时长,如果保存应用程序无法确定的话。如果文件路径指向网络电台流,则曲目名称显示 URL,曲目时长不确定。

Vista 和 UAC
为了使此 Shell 扩展能与 UAC 良好协作,必须将 DLL 添加到已知 DLL 列表中。
HKLM
{
NoRemove Software
{
NoRemove Microsoft
{
NoRemove Windows
{
NoRemove CurrentVersion
{
NoRemove 'Shell Extensions'
{
NoRemove Approved
{
val {A191B386-C1C7-4fb5-AD9D-6979C21CE44B} = s 'PlsTip Class'
...
代码重用
要将解析扩展到其他播放列表格式(如 wpl 等),您需要将您的提示信息生成函数放在 CBmpTip::GetBitmapInfo
成员中,在 PlaylistGlobals.h 中的 PLAYLIST_TYPE
枚举和 C_PlaylistParser::getType
中添加新的文件扩展名,并在 switch(playlistType)
块中添加新的解析函数。
还需要在 BmpTip.rgs 和 BmpTip.idl 文件中添加必要的注册表项。
要创建一个全新的提示信息扩展,请将您的新提示信息生成函数放在 CBmpTip::GetBitmapInfo
成员中,并更改 BmpTip.rgs 和 BmpTip.idl 文件中的 CLSID。
在可能的情况下实现了有限的错误纠正,但它不像普通程序那样是防错的,因为我不期望解析手工制作的播放列表(可能包含错误)。该代码最适合应用程序生成的播放列表,因为它们不太可能包含结构性错误。项目包附带了一些测试文件,因此您可以进行自己的测试。