PowerToys
PowerToys copied to clipboard
FancyZones reads json files __continuously__
Microsoft PowerToys version
v0.73.0
Installation method
GitHub, PowerToys auto-update
Running as admin
Yes
Area(s) with issue?
FancyZones
Steps to reproduce
apparently, it's "install fancy zones" and turn on "promon" and watch for *.json files and notice tons of reads that should not be happening....
✔️ Expected Behavior
I expect it to add a file watcher and not poll/read these json files over and over again.
❌ Actual Behavior
fancy zones reads custom-layouts.json, settings.json, layout-templates.json, applied-layouts.json over and over and over and over and over....... please stop?
Other Software
No response
I didn't find this issue when searching before submitting my own. My report provides much more detail... Please fix this. It's quite concerning.
Still an issue in v0.76.2, it's a major concern esp. if someone is still using a spinning platter HDD as a primary drive.
I took a look into this and the behavour is caused by PowerToys FileWatcher that is used by FZ, AOT and VCM.
PowerToys isn't really reading the file every second but just checking the last write time.
Last write time check:
Actual read:
@jaimecbernardo any thoughts on this?
Wonder if there's another API we can use for this or if that's just the way to do it on Windows 🤔 Setting it to a project so that it can be investigated. Wondering if we should be using other synchronization methods instead, like Events.
I was curios so I have investigated a little bit: C# FileSystemWatcher is based on ReadDirectoryChangesW.
The API is not a simple one to use (at least for me) but I figured out that Windows Implementation Libraries have a nice wrapper to consume it.
Since this is a core API I am fine with @yuyoyuppe working on this but I want to add this as it might be useful input 😃
I Tried this and at a sight is working but more tests are needed:
FileWatcher::FileWatcher(const std::wstring& path, std::function<void()> callback) :
m_callback(callback)
{
size_t pos = path.find_last_of(L"\\/");
if (pos != std::wstring::npos && pos + 1 < path.length())
{
std::wstring folder = path.substr(0, pos);
m_file = path.substr(pos + 1);
std::transform(m_file.begin(), m_file.end(), m_file.begin(), ::towlower);
m_folder_change_reader.create(
folder.c_str(),
false,
wil::FolderChangeEvents::LastWriteTime,
[&](wil::FolderChangeEvent, PCWSTR fileName)
{
std::wstring lowerfileName(fileName);
std::transform(lowerfileName.begin(), lowerfileName.end(), lowerfileName.begin(), ::towlower);
if (m_file.compare(fileName) == 0)
{
m_callback();
}
});
if (!m_folder_change_reader)
{
Logger::error(L"Failed to start file watcher for {}", path);
}
}
}
@davidegiacometti thanks, that looks good! I'd just change it to use wil::make_folder_change_reader instead of .create and use std::filesystem APIs for parsing the filename. Feel free to open a PR or I can do it a bit later. 🙂
Hi, this has been worked on for the 0.78 development cycle. 😄 Please update PowerToys to the latest: https://github.com/microsoft/PowerToys/releases
procmon confirms that PowerToys is no longer so overzealous with files.
Thanks so much