Skip to content

Commit

Permalink
修正资源管理器多选打开时的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
lrisora committed Sep 14, 2023
1 parent eca5de3 commit 404374e
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 63 deletions.
20 changes: 10 additions & 10 deletions MusicPlayer2/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,12 +928,18 @@ void CCommon::WriteLog(const wchar_t* path, const wstring& content)
cur_time.wHour, cur_time.wMinute, cur_time.wSecond, cur_time.wMilliseconds);
ofstream out_put{ path, std::ios::app };
out_put << buff << CCommon::UnicodeToStr(content, CodeType::UTF8_NO_BOM) << std::endl;
out_put.close(); // 这里需要显式关闭以避免被不同线程连续调用时丢失内容(不过还是不能承受并发,多线程并发时请自行加锁
}

wstring CCommon::DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files)
void CCommon::DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files)
{
// 解析命令行参数中的文件/文件夹路径放入files
// files 中能够接受音频文件路径/播放列表文件路径/文件夹路径随意乱序出现
// files 中无法被识别为“播放列表文件路径”“文件夹路径”的项目会被直接加入默认播放列表
// TODO: 这里可能需要添加以下功能,我没有其他windows版本的经验,不确定这里怎样改
// 文件/文件夹存在判断;路径通配符展开;相对路径转换绝对路径;支持不在同一文件夹下的多个文件路径
files.clear();
if (cmd_line.empty()) return wstring();
if (cmd_line.empty()) return;
wstring path;
//先找出字符串中的文件夹路径,从命令行参数传递过来的文件肯定都是同一个文件夹下的
if (cmd_line[0] == L'\"') //如果第一个文件用双引号包含起来
Expand All @@ -951,13 +957,7 @@ wstring CCommon::DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& f
files.push_back(cmd_line.substr(0, index1));
}
int path_size = path.size();
if (path_size < 2) return wstring();
if (IsFolder(files[0]))
//if (files[0].size() > 4 && files[0][files[0].size() - 4] != L'.' && files[0][files[0].size() - 5] != L'.')
{
//如果第1个文件不是文件而是文件夹,则返直接回该文件夹的路径
return files[0];
}
if (path_size < 2) return;
int index{};
while (true)
{
Expand All @@ -974,7 +974,7 @@ wstring CCommon::DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& f
files.push_back(cmd_line.substr(index, index1 - index));
}
}
return wstring();
return;
//CString out_info;
//out_info += _T("命令行参数:");
//out_info += cmd_line.c_str();
Expand Down
4 changes: 2 additions & 2 deletions MusicPlayer2/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ class CCommon
//写入日志
static void WriteLog(const wchar_t* path, const wstring& content);

//将通过命令行参数传递过来的多个文件路径拆分,并保存到file容器里,如果参数传递过来的第一个文件不是文件而是文件夹,则返回文件夹路径,否则,返回空字符串
static wstring DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files);
// 将通过命令行参数传递过来的多个文件路径拆分,并保存到file容器里
static void DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files);

//解析命令行参数中的命令
static bool GetCmdLineCommand(const wstring& cmd_line, int& command);
Expand Down
1 change: 1 addition & 0 deletions MusicPlayer2/Define.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ using _tstring = std::string;
#define TIMER_1_SEC 1237
#define TIMER_DESKTOP_LYRIC 1238
#define TIMER_DESKTOP_LYRIC_2 1239
#define TIMER_CMD_OPEN_FILES_DELAY 1240

#define UI_INTERVAL_DEFAULT 50 //定义界面刷新时间的默认时间间隔(毫秒)
#define MIN_UI_INTERVAL 10 //界面刷新时间间隔最小值
Expand Down
128 changes: 106 additions & 22 deletions MusicPlayer2/MusicPlayerDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,7 @@ void CMusicPlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

static bool cmd_open_files_ing{ false }; // 用于阻止TIMER_CMD_OPEN_FILES_DELAY重入
//响应主定时器
if (nIDEvent == TIMER_ID)
{
Expand Down Expand Up @@ -2454,20 +2455,35 @@ void CMusicPlayerDlg::OnTimer(UINT_PTR nIDEvent)
}
else //从命令行参数获取要打开的文件
{
bool open_default_playlist{ true };
vector<wstring> files;
wstring path = CCommon::DisposeCmdLineFiles(m_cmdLine, files);
if (!path.empty())
CCommon::DisposeCmdLineFiles(m_cmdLine, files);
if (!files.empty())
{
CPlayer::GetInstance().CreateWithPath(path);
if (CPlaylistFile::IsPlaylistFile(files.front()))
{
CPlayer::GetInstance().CreateWithPlaylist(files.front());
files.erase(files.begin());
open_default_playlist = false;
}
else if (CCommon::IsFolder(files.front()))
{
CPlayer::GetInstance().CreateWithPath(files.front());
files.erase(files.begin());
open_default_playlist = false;
}
}
else
if (open_default_playlist)
{
if (!files.empty() && CPlaylistFile::IsPlaylistFile(files[0]))
CPlayer::GetInstance().CreateWithPlaylist(files[0]);
else
CPlayer::GetInstance().CreateWithFiles(files);
CPlayer::GetInstance().CreateWithPlaylist(theApp.m_playlist_dir + DEFAULT_PLAYLIST_NAME);
}
if (!files.empty())
{
std::unique_lock<std::mutex> lock(m_cmd_open_files_mutx);
// theApp.WriteLog(m_cmdLine + L"<from_first_timer>");
m_cmd_open_files.insert(m_cmd_open_files.begin(), files.begin(), files.end()); // 当前实例成功创建互斥量,故插入到开头
SetTimer(TIMER_CMD_OPEN_FILES_DELAY, 1000, nullptr);
}
//MessageBox(m_cmdLine.c_str(), NULL, MB_ICONINFORMATION);
}
DrawInfo();
m_uiThread = AfxBeginThread(UiThreadFunc, (LPVOID)&m_ui_thread_para);
Expand Down Expand Up @@ -2668,6 +2684,81 @@ void CMusicPlayerDlg::OnTimer(UINT_PTR nIDEvent)
cur_ui->ResetVolumeToPlayTime();
}

// 距最后一次设置此定时器1s,说明已经1s没有收到copy_data消息,将m_cmd_open_files内容设为当前播放
else if (nIDEvent == TIMER_CMD_OPEN_FILES_DELAY && !cmd_open_files_ing)
{
cmd_open_files_ing = true;
// 这里会在一次一次的回调中先逐个打开并移除m_cmd_open_files中的播放列表/文件夹条目
// m_cmd_open_files中不含播放列表/文件夹后将剩余歌曲一次在默认播放列表打开并清空m_cmd_open_files
// m_cmd_open_files为空后再KillTimer
wstring path_playlist, path_folder, path_playlist_new;
vector<wstring> path_songs;
m_cmd_open_files_mutx.lock();
auto iter_p = std::find_if(m_cmd_open_files.begin(), m_cmd_open_files.end(),
[&](const wstring& path) { return CPlaylistFile::IsPlaylistFile(path); });
if (iter_p != m_cmd_open_files.end())
path_playlist = *iter_p;
else
{
auto iter_f = std::find_if(m_cmd_open_files.begin(), m_cmd_open_files.end(),
[&](const wstring& path) { return CCommon::IsFolder(path); });
if (iter_f != m_cmd_open_files.end())
path_folder = *iter_f;
else
path_songs = m_cmd_open_files;
}
m_cmd_open_files_mutx.unlock();
// CPlayer的初始化方法会向主线程发消息而主线程的copy_data有可能正在等待获取这个锁故需要先解锁,否则有可能死锁
if (!path_playlist.empty())
{
path_playlist_new = path_playlist;
if (CPlayer::GetInstance().OpenPlaylistFile(path_playlist_new)) // 注意OpenPlaylistFile会修改参数,需将修改结果反映到m_cmd_open_files,防止反复复制播放列表
path_playlist_new.clear(); // 下面的行为是path_playlist_new为空直接移除path_playlist,否则将m_cmd_open_files中的path_playlist替换为path_playlist_new
}
else if (!path_folder.empty())
{
if (!CPlayer::GetInstance().OpenFolder(path_folder))
path_folder.clear();
}
else
{
if (!CPlayer::GetInstance().OpenFilesInDefaultPlaylist(path_songs))
path_songs.clear();
}
m_cmd_open_files_mutx.lock();
if (!path_playlist.empty())
{
auto iter = std::find(m_cmd_open_files.begin(), m_cmd_open_files.end(), path_playlist);
if (iter != m_cmd_open_files.end())
{
if (!path_playlist_new.empty())
*iter = path_playlist_new;
else
m_cmd_open_files.erase(iter);
}
}
else if (!path_folder.empty())
{
auto iter = std::find(m_cmd_open_files.begin(), m_cmd_open_files.end(), path_folder);
if (iter != m_cmd_open_files.end())
{
m_cmd_open_files.erase(iter);
}
}
else if (!path_songs.empty())
{
// 因为中间解锁过所以m_cmd_open_files和path_songs不一定相同,不能直接清空m_cmd_open_files
auto new_end = std::remove_if(m_cmd_open_files.begin(), m_cmd_open_files.end(),
[&](const wstring& path) { return CCommon::IsItemInVector(path_songs, path); });
m_cmd_open_files.erase(new_end, m_cmd_open_files.end());
}
// 如果m_cmd_open_files已全部处理完成则关闭定时器,否则下次时间到再尝试
if (m_cmd_open_files.empty())
KillTimer(TIMER_CMD_OPEN_FILES_DELAY);
m_cmd_open_files_mutx.unlock();
cmd_open_files_ing = false;
}

CMainDialogBase::OnTimer(nIDEvent);
}

Expand Down Expand Up @@ -6112,19 +6203,12 @@ BOOL CMusicPlayerDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
if (cmd_line.empty())
return 0;
vector<wstring> files;
CCommon::DisposeCmdLineFiles(wstring(cmd_line), files);
if (pCopyDataStruct->dwData == COPY_DATA_OPEN_FILE)
{
if (!files.empty() && CPlaylistFile::IsPlaylistFile(files[0]))
CPlayer::GetInstance().OpenPlaylistFile(files[0]);
else
CPlayer::GetInstance().OpenFilesInDefaultPlaylist(files);
}
else if (pCopyDataStruct->dwData == COPY_DATA_ADD_FILE)
{
if (CPlayer::GetInstance().IsPlaylistMode())
CPlayer::GetInstance().AddFilesToPlaylist(files, true);
}
CCommon::DisposeCmdLineFiles(cmd_line, files);
// 这里不再区分COPY_DATA_OPEN_FILE和COPY_DATA_ADD_FILE,统一处理
std::unique_lock<std::mutex> lock(m_cmd_open_files_mutx);
// theApp.WriteLog(cmd_line + L"<from_copy_data>");
m_cmd_open_files.insert(m_cmd_open_files.end(), files.begin(),files.end()); // 将来自其他实例的cmd追加到末尾
SetTimer(TIMER_CMD_OPEN_FILES_DELAY, 1000, nullptr);
}
}

Expand Down
2 changes: 2 additions & 0 deletions MusicPlayer2/MusicPlayerDlg.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class CMusicPlayerDlg : public CMainDialogBase
HACCEL m_hAccel{};

wstring m_cmdLine; //命令行参数
std::mutex m_cmd_open_files_mutx; // 保护m_cmd_open_files的线程同步对象
vector<wstring> m_cmd_open_files; // 来自命令行/copy_data的待打开文件队列

CDC* m_pUiDC; //当前窗口的DC
std::vector<std::shared_ptr<CPlayerUIBase>> m_ui_list; //保存每个界面类的指针
Expand Down
44 changes: 25 additions & 19 deletions MusicPlayer2/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ void CPlayer::CreateWithPlaylist(const wstring& playlist_path)
LoadConfig();
LoadRecentPath();
LoadRecentPlaylist();
OpenPlaylistFile(playlist_path);
wstring tmp{ playlist_path };
OpenPlaylistFile(tmp);
SetTitle();
m_controls.Init();
}
Expand Down Expand Up @@ -972,7 +973,6 @@ void CPlayer::LoopPlaylist(int& song_track)

void CPlayer::ChangePath(const wstring& path, int track, bool play, int position)
{
MusicControl(Command::CLOSE);
m_path = path;
if (m_path.empty() || (m_path.back() != L'/' && m_path.back() != L'\\')) //如果输入的新路径为空或末尾没有斜杠,则在末尾加上一个
m_path.append(1, L'\\');
Expand All @@ -983,8 +983,6 @@ void CPlayer::ChangePath(const wstring& path, int track, bool play, int position
m_current_position.fromInt(position);
SaveConfig();
SetTitle();
//MusicControl(Command::OPEN);
//IniLyrics();
}

void CPlayer::SetPath(const PathInfo& path_info)
Expand All @@ -994,6 +992,8 @@ void CPlayer::SetPath(const PathInfo& path_info)
m_loading = true;
IniPlayerCore();

MusicControl(Command::CLOSE);

if (GetSongNum() > 0)
{
SaveCurrentPlaylist();
Expand All @@ -1016,10 +1016,10 @@ void CPlayer::SetPath(const PathInfo& path_info)

}

void CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position, bool init, bool play, bool force)
bool CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position, bool init, bool play, bool force)
{
if (m_loading) return;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return;
if (m_loading) return false;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;
m_loading = true;
IniPlayerCore();

Expand Down Expand Up @@ -1069,15 +1069,18 @@ void CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position,
EmplaceCurrentPlaylistToRecent();

IniPlayList(true, false, play);
return true;
}

void CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play)
bool CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play)
{
if (m_loading) return;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return;
if (m_loading) return false;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;
m_loading = true;
IniPlayerCore();

MusicControl(Command::CLOSE);

if (path.empty() || (path.back() != L'/' && path.back() != L'\\')) //如果打开的新路径为空或末尾没有斜杠,则在末尾加上一个
path.append(1, L'\\');
bool path_exist{ false };
Expand Down Expand Up @@ -1115,21 +1118,22 @@ void CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play)
}
EmplaceCurrentPathToRecent(); //保存打开的路径到最近路径
SaveRecentPath();
return true;
}

void CPlayer::OpenFilesInDefaultPlaylist(const vector<wstring>& files, bool play)
bool CPlayer::OpenFilesInDefaultPlaylist(const vector<wstring>& files, bool play)
{
vector<SongInfo> songs(files.size());
for (size_t i{}; i < files.size(); ++i)
songs[i].file_path = files[i];
OpenSongsInDefaultPlaylist(songs, play);
return OpenSongsInDefaultPlaylist(songs, play);
}

void CPlayer::OpenSongsInDefaultPlaylist(const vector<SongInfo>& songs, bool play)
bool CPlayer::OpenSongsInDefaultPlaylist(const vector<SongInfo>& songs, bool play)
{
if (songs.empty()) return;
if (m_loading) return;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return;
if (songs.empty()) return false;
if (m_loading) return false;
if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false;
m_loading = true;
IniPlayerCore();

Expand Down Expand Up @@ -1172,6 +1176,7 @@ void CPlayer::OpenSongsInDefaultPlaylist(const vector<SongInfo>& songs, bool pla
SetTitle(); //用当前正在播放的歌曲名作为窗口标题

IniPlayList(true, false, play);
return true;
}

void CPlayer::OpenSongsInTempPlaylist(const vector<SongInfo>& songs, int play_index, bool play /*= true*/)
Expand Down Expand Up @@ -1251,7 +1256,7 @@ void CPlayer::OpenASongInFolderMode(const SongInfo& song, bool play)
IniPlayList(false, false, play); //根据新路径重新初始化播放列表
}

void CPlayer::OpenPlaylistFile(const wstring& file_path)
bool CPlayer::OpenPlaylistFile(wstring& file_path)
{
CFilePathHelper helper(file_path);
if (!CCommon::StringCompareNoCase(helper.GetDir(), theApp.m_playlist_dir)) //如果打开的播放列表文件不是程序默认的播放列表目录,则将其转换为*.playlist格式并复制到默认的播放列表目录
Expand All @@ -1264,13 +1269,14 @@ void CPlayer::OpenPlaylistFile(const wstring& file_path)
CPlaylistFile playlist;
playlist.LoadFromFile(file_path);
playlist.SaveToFile(new_path);
file_path = new_path;

SetPlaylist(new_path, 0, 0);
return SetPlaylist(new_path, 0, 0);
}
else //如果打开的播放文件就在默认播放列表目录下,则直接打开
{
auto path_info = CPlaylistMgr::Instance().FindPlaylistInfo(file_path);
SetPlaylist(file_path, path_info.track, path_info.position);
return SetPlaylist(file_path, path_info.track, path_info.position);
}

}
Expand Down
Loading

0 comments on commit 404374e

Please sign in to comment.