mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-23 12:37:31 +01:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This pull request introduces a new command-line interface (CLI) project for the File Locksmith module, enabling users to interact with File Locksmith functionality directly from the command line. The changes include project and build configuration, CLI implementation, and supporting code to integrate with the existing FileLocksmith library. ## Commands and Options | Command / Option | Alias | Description | | :--- | :--- | :--- | | `<path>` | N/A | **Required**. One or more file or directory paths to check. You can specify multiple paths separated by spaces. | | `--kill` | N/A | Terminates (kills) all processes that are currently locking the specified files. | | `--json` | N/A | Outputs the results in structured **JSON** format instead of human-readable text. Useful for automation and scripts. | | `--wait` | N/A | **Blocks execution** and waits until the specified files are released. The command will not exit until the files are unlocked. | | `--help` | N/A | Displays the help message with usage instructions. | ## Usage Examples ### 1. Basic check (Human-readable output) Check which processes are locking a specific file: ```powershell FileLocksmithCLI.exe "C:\Users\Docs\report.docx" ``` ### 2. Check multiple files and output JSON Check multiple files and get the output in JSON format for parsing: ```powershell FileLocksmithCLI.exe --json "C:\File1.txt" "C:\Folder\File2.dll" ``` ### 3. Wait for a file to be unlocked Block script execution until a file is released (useful in build scripts): ```powershell FileLocksmithCLI.exe --wait "C:\bin\output.exe" ``` ### 4. Force unlock a file Kill all processes that are locking a specific file: ```powershell FileLocksmithCLI.exe --kill "C:\LockedFile.dat" ``` <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed --------- Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
115 lines
3.1 KiB
C++
115 lines
3.1 KiB
C++
#include "pch.h"
|
|
#include "Settings.h"
|
|
#include "Constants.h"
|
|
|
|
#include <filesystem>
|
|
#include <common/utils/json.h>
|
|
#include <common/SettingsAPI/settings_helpers.h>
|
|
|
|
static bool LastModifiedTime(const std::wstring& filePath, FILETIME* lpFileTime)
|
|
{
|
|
WIN32_FILE_ATTRIBUTE_DATA attr{};
|
|
if (GetFileAttributesExW(filePath.c_str(), GetFileExInfoStandard, &attr))
|
|
{
|
|
*lpFileTime = attr.ftLastWriteTime;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FileLocksmithSettings::FileLocksmithSettings()
|
|
{
|
|
generalJsonFilePath = PTSettingsHelper::get_powertoys_general_save_file_location();
|
|
std::wstring savePath = PTSettingsHelper::get_module_save_folder_location(constants::nonlocalizable::PowerToyKey);
|
|
std::error_code ec;
|
|
|
|
jsonFilePath = savePath + constants::nonlocalizable::DataFilePath;
|
|
RefreshEnabledState();
|
|
Load();
|
|
}
|
|
|
|
void FileLocksmithSettings::Save()
|
|
{
|
|
json::JsonObject jsonData;
|
|
|
|
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::value(settings.showInExtendedContextMenu));
|
|
|
|
json::to_file(jsonFilePath, jsonData);
|
|
GetSystemTimeAsFileTime(&lastLoadedTime);
|
|
}
|
|
|
|
void FileLocksmithSettings::Load()
|
|
{
|
|
if (!std::filesystem::exists(jsonFilePath))
|
|
{
|
|
Save();
|
|
}
|
|
else
|
|
{
|
|
ParseJson();
|
|
}
|
|
}
|
|
|
|
void FileLocksmithSettings::RefreshEnabledState()
|
|
{
|
|
// Load json settings from data file if it is modified in the meantime.
|
|
FILETIME lastModifiedTime{};
|
|
if (!(LastModifiedTime(generalJsonFilePath, &lastModifiedTime) &&
|
|
CompareFileTime(&lastModifiedTime, &lastLoadedGeneralSettingsTime) == 1))
|
|
return;
|
|
|
|
lastLoadedGeneralSettingsTime = lastModifiedTime;
|
|
|
|
auto json = json::from_file(generalJsonFilePath);
|
|
if (!json)
|
|
return;
|
|
|
|
const json::JsonObject& jsonSettings = json.value();
|
|
try
|
|
{
|
|
json::JsonObject modulesEnabledState;
|
|
json::get(jsonSettings, L"enabled", modulesEnabledState, json::JsonObject{});
|
|
json::get(modulesEnabledState, L"File Locksmith", settings.enabled, true);
|
|
}
|
|
catch (const winrt::hresult_error&)
|
|
{
|
|
}
|
|
}
|
|
|
|
void FileLocksmithSettings::Reload()
|
|
{
|
|
// Load json settings from data file if it is modified in the meantime.
|
|
FILETIME lastModifiedTime{};
|
|
if (LastModifiedTime(jsonFilePath, &lastModifiedTime) &&
|
|
CompareFileTime(&lastModifiedTime, &lastLoadedTime) == 1)
|
|
{
|
|
Load();
|
|
}
|
|
}
|
|
|
|
void FileLocksmithSettings::ParseJson()
|
|
{
|
|
auto json = json::from_file(jsonFilePath);
|
|
if (json)
|
|
{
|
|
const json::JsonObject& jsonSettings = json.value();
|
|
try
|
|
{
|
|
if (json::has(jsonSettings, constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::JsonValueType::Boolean))
|
|
{
|
|
settings.showInExtendedContextMenu = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu);
|
|
}
|
|
}
|
|
catch (const winrt::hresult_error&)
|
|
{
|
|
}
|
|
}
|
|
GetSystemTimeAsFileTime(&lastLoadedTime);
|
|
}
|
|
|
|
FileLocksmithSettings& FileLocksmithSettingsInstance()
|
|
{
|
|
static FileLocksmithSettings instance;
|
|
return instance;
|
|
}
|