[SHELL32] Update the status bar asynchronously (#5420)

- Selecting all in system32 was too slow.
- Make CDefView::UpdateStatusbar function asynchronized by using a thread.
- It makes selecting all very quick.
- Add m_hUpdateStatusbarThread to asynchronize.
CORE-18663
This commit is contained in:
Katayama Hirofumi MZ 2023-07-12 22:24:04 +09:00 committed by GitHub
parent 8d821292de
commit 9a1487f3a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -36,6 +36,7 @@ TODO:
#include "precomp.h" #include "precomp.h"
#include <process.h>
#include <atlwin.h> #include <atlwin.h>
#include <ui/rosctrls.h> #include <ui/rosctrls.h>
@ -153,6 +154,7 @@ class CDefView :
SFVM_CUSTOMVIEWINFO_DATA m_viewinfo_data; SFVM_CUSTOMVIEWINFO_DATA m_viewinfo_data;
HICON m_hMyComputerIcon; HICON m_hMyComputerIcon;
HANDLE m_hUpdateStatusbarThread;
private: private:
HRESULT _MergeToolbar(); HRESULT _MergeToolbar();
@ -171,6 +173,8 @@ class CDefView :
HRESULT IncludeObject(PCUITEMID_CHILD pidl); HRESULT IncludeObject(PCUITEMID_CHILD pidl);
HRESULT OnDefaultCommand(); HRESULT OnDefaultCommand();
HRESULT OnStateChange(UINT uFlags); HRESULT OnStateChange(UINT uFlags);
static unsigned __stdcall _UpdateStatusbarProc(void *args);
void UpdateStatusbarWorker(HANDLE hThread);
void UpdateStatusbar(); void UpdateStatusbar();
void CheckToolbar(); void CheckToolbar();
BOOL CreateList(); BOOL CreateList();
@ -428,7 +432,9 @@ CDefView::CDefView() :
m_cScrollDelay(0), m_cScrollDelay(0),
m_isEditing(FALSE), m_isEditing(FALSE),
m_isParentFolderSpecial(FALSE), m_isParentFolderSpecial(FALSE),
m_Destroyed(FALSE) m_Destroyed(FALSE),
m_hMyComputerIcon(::LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_COMPUTER_DESKTOP))),
m_hUpdateStatusbarThread(NULL)
{ {
ZeroMemory(&m_FolderSettings, sizeof(m_FolderSettings)); ZeroMemory(&m_FolderSettings, sizeof(m_FolderSettings));
ZeroMemory(&m_sortInfo, sizeof(m_sortInfo)); ZeroMemory(&m_sortInfo, sizeof(m_sortInfo));
@ -437,8 +443,6 @@ CDefView::CDefView() :
m_viewinfo_data.clrText = GetSysColor(COLOR_WINDOWTEXT); m_viewinfo_data.clrText = GetSysColor(COLOR_WINDOWTEXT);
m_viewinfo_data.clrTextBack = GetSysColor(COLOR_WINDOW); m_viewinfo_data.clrTextBack = GetSysColor(COLOR_WINDOW);
m_viewinfo_data.hbmBack = NULL; m_viewinfo_data.hbmBack = NULL;
m_hMyComputerIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_COMPUTER_DESKTOP));
} }
CDefView::~CDefView() CDefView::~CDefView()
@ -539,10 +543,9 @@ void CDefView::CheckToolbar()
} }
} }
void CDefView::UpdateStatusbar() void CDefView::UpdateStatusbarWorker(HANDLE hThread)
{ {
WCHAR szFormat[MAX_PATH] = {0}; WCHAR szFormat[MAX_PATH], szPartText[MAX_PATH];
WCHAR szPartText[MAX_PATH] = {0};
UINT cSelectedItems; UINT cSelectedItems;
cSelectedItems = m_ListView.GetSelectedCount(); cSelectedItems = m_ListView.GetSelectedCount();
@ -571,12 +574,13 @@ void CDefView::UpdateStatusbar()
/* If we have something selected then only count selected file sizes. */ /* If we have something selected then only count selected file sizes. */
if (cSelectedItems) if (cSelectedItems)
{
uFileFlags = LVNI_SELECTED; uFileFlags = LVNI_SELECTED;
}
while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0) while ((nItem = m_ListView.GetNextItem(nItem, uFileFlags)) >= 0)
{ {
if (hThread != m_hUpdateStatusbarThread)
return;
PCUITEMID_CHILD pidl = _PidlByItem(nItem); PCUITEMID_CHILD pidl = _PidlByItem(nItem);
uTotalFileSize += _ILGetFileSize(pidl, NULL, 0); uTotalFileSize += _ILGetFileSize(pidl, NULL, 0);
@ -589,18 +593,14 @@ void CDefView::UpdateStatusbar()
/* Don't show the file size text if there is 0 bytes in the folder /* Don't show the file size text if there is 0 bytes in the folder
* OR we only have folders selected. */ * OR we only have folders selected. */
szPartText[0] = UNICODE_NULL;
if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize) if ((cSelectedItems && !bIsOnlyFoldersSelected) || uTotalFileSize)
{
StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText)); StrFormatByteSizeW(uTotalFileSize, szPartText, _countof(szPartText));
}
else
{
*szPartText = 0;
}
m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult); m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, 1, (LPARAM)szPartText, &lResult);
/* If we are in a Recycle Bin folder then show no text for the location part. */ /* If we are in a Recycle Bin folder then show no text for the location part. */
szPartText[0] = UNICODE_NULL;
if (!_ILIsBitBucket(m_pidlParent)) if (!_ILIsBitBucket(m_pidlParent))
{ {
LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText)); LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szPartText, _countof(szPartText));
@ -612,6 +612,38 @@ void CDefView::UpdateStatusbar()
} }
} }
unsigned __stdcall CDefView::_UpdateStatusbarProc(void *args)
{
CDefView* pView = static_cast<CDefView*>(args);
pView->UpdateStatusbarWorker(pView->m_hUpdateStatusbarThread);
pView->Release();
return 0;
}
void CDefView::UpdateStatusbar()
{
HANDLE hOldThread = m_hUpdateStatusbarThread;
AddRef();
// We have to initialize m_hUpdateStatusbarThread before the target thread begins.
// So, we use CREATE_SUSPENDED.
HANDLE hNewThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, _UpdateStatusbarProc,
this, CREATE_SUSPENDED, NULL));
if (hNewThread)
{
m_hUpdateStatusbarThread = hNewThread;
::ResumeThread(hNewThread);
if (hOldThread)
::CloseHandle(hOldThread);
}
else
{
Release();
}
}
/********************************************************** /**********************************************************
* *
* ##### helperfunctions for initializing the view ##### * ##### helperfunctions for initializing the view #####
@ -2582,6 +2614,17 @@ HRESULT WINAPI CDefView::DestroyViewWindow()
{ {
TRACE("(%p)\n", this); TRACE("(%p)\n", this);
if (m_hUpdateStatusbarThread)
{
HANDLE hOldThread = m_hUpdateStatusbarThread;
// Assigning NULL to m_hUpdateStatusbarThread will terminate the target thread immediately
m_hUpdateStatusbarThread = NULL;
::WaitForSingleObject(hOldThread, INFINITE);
::CloseHandle(hOldThread);
}
/* Make absolutely sure all our UI is cleaned up */ /* Make absolutely sure all our UI is cleaned up */
UIActivate(SVUIA_DEACTIVATE); UIActivate(SVUIA_DEACTIVATE);