Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
This commit is contained in:
Shawn Yuan (from Dev Box)
2025-12-05 14:37:16 +08:00
parent 73e2c4dfb5
commit 636b2a500b

View File

@@ -2,18 +2,27 @@
#include "FileLocksmithLib/FileLocksmith.h" #include "FileLocksmithLib/FileLocksmith.h"
#include <common/utils/json.h> #include <common/utils/json.h>
#include <iostream> #include <iostream>
#include <sstream>
void print_usage() struct CommandResult
{ {
std::wcout << L"Usage: FileLocksmithCLI.exe [options] <path1> [path2] ...\n" int exit_code;
std::wstring output;
};
std::wstring get_usage()
{
std::wstringstream ss;
ss << L"Usage: FileLocksmithCLI.exe [options] <path1> [path2] ...\n"
<< L"Options:\n" << L"Options:\n"
<< L" --kill Kill processes locking the files\n" << L" --kill Kill processes locking the files\n"
<< L" --json Output results in JSON format\n" << L" --json Output results in JSON format\n"
<< L" --wait Wait for files to be unlocked\n" << L" --wait Wait for files to be unlocked\n"
<< L" --help Show this help message\n"; << L" --help Show this help message\n";
return ss.str();
} }
void print_json(const std::vector<ProcessResult>& results) std::wstring get_json(const std::vector<ProcessResult>& results)
{ {
json::JsonObject root; json::JsonObject root;
json::JsonArray processes; json::JsonArray processes;
@@ -36,28 +45,31 @@ void print_json(const std::vector<ProcessResult>& results)
} }
root.SetNamedValue(L"processes", processes); root.SetNamedValue(L"processes", processes);
std::wcout << root.Stringify().c_str() << std::endl; return root.Stringify();
} }
void print_text(const std::vector<ProcessResult>& results) std::wstring get_text(const std::vector<ProcessResult>& results)
{ {
std::wstringstream ss;
if (results.empty()) if (results.empty())
{ {
std::wcout << L"No processes found locking the file(s)." << std::endl; ss << L"No processes found locking the file(s)." << std::endl;
return; return ss.str();
} }
std::wcout << L"PID\tUser\tProcess" << std::endl; ss << L"PID\tUser\tProcess" << std::endl;
for (const auto& result : results) for (const auto& result : results)
{ {
std::wcout << result.pid << L"\t" ss << result.pid << L"\t"
<< result.user << L"\t" << result.user << L"\t"
<< result.name << std::endl; << result.name << std::endl;
} }
return ss.str();
} }
void kill_processes(const std::vector<ProcessResult>& results) std::wstring kill_processes(const std::vector<ProcessResult>& results)
{ {
std::wstringstream ss;
for (const auto& result : results) for (const auto& result : results)
{ {
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, result.pid); HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, result.pid);
@@ -65,29 +77,27 @@ void kill_processes(const std::vector<ProcessResult>& results)
{ {
if (TerminateProcess(hProcess, 0)) if (TerminateProcess(hProcess, 0))
{ {
std::wcout << L"Terminated process " << result.pid << L" (" << result.name << L")" << std::endl; ss << L"Terminated process " << result.pid << L" (" << result.name << L")" << std::endl;
} }
else else
{ {
std::wcerr << L"Failed to terminate process " << result.pid << L" (" << result.name << L")" << std::endl; ss << L"Failed to terminate process " << result.pid << L" (" << result.name << L")" << std::endl;
} }
CloseHandle(hProcess); CloseHandle(hProcess);
} }
else else
{ {
std::wcerr << L"Failed to open process " << result.pid << L" (" << result.name << L")" << std::endl; ss << L"Failed to open process " << result.pid << L" (" << result.name << L")" << std::endl;
} }
} }
return ss.str();
} }
int wmain(int argc, wchar_t* argv[]) CommandResult run_command(int argc, wchar_t* argv[])
{ {
winrt::init_apartment();
if (argc < 2) if (argc < 2)
{ {
print_usage(); return { 1, get_usage() };
return 1;
} }
bool json_output = false; bool json_output = false;
@@ -112,8 +122,7 @@ int wmain(int argc, wchar_t* argv[])
} }
else if (arg == L"--help") else if (arg == L"--help")
{ {
print_usage(); return { 0, get_usage() };
return 0;
} }
else else
{ {
@@ -123,49 +132,58 @@ int wmain(int argc, wchar_t* argv[])
if (paths.empty()) if (paths.empty())
{ {
std::wcerr << L"Error: No paths specified." << std::endl; return { 1, L"Error: No paths specified.\n" };
return 1;
} }
if (wait) if (wait)
{ {
std::wstringstream ss;
if (json_output) if (json_output)
{ {
std::wcerr << L"Warning: --wait is incompatible with --json. Ignoring --json." << std::endl; ss << L"Warning: --wait is incompatible with --json. Ignoring --json." << std::endl;
json_output = false; json_output = false;
} }
std::wcout << L"Waiting for files to be unlocked..." << std::endl; ss << L"Waiting for files to be unlocked..." << std::endl;
while (true) while (true)
{ {
auto results = find_processes_recursive(paths); auto results = find_processes_recursive(paths);
if (results.empty()) if (results.empty())
{ {
std::wcout << L"Files unlocked." << std::endl; ss << L"Files unlocked." << std::endl;
break; break;
} }
Sleep(1000); Sleep(1000);
} }
return 0; return { 0, ss.str() };
} }
auto results = find_processes_recursive(paths); auto results = find_processes_recursive(paths);
std::wstringstream output_ss;
if (kill) if (kill)
{ {
kill_processes(results); output_ss << kill_processes(results);
// Re-check after killing // Re-check after killing
results = find_processes_recursive(paths); results = find_processes_recursive(paths);
} }
if (json_output) if (json_output)
{ {
print_json(results); output_ss << get_json(results) << std::endl;
} }
else else
{ {
print_text(results); output_ss << get_text(results);
} }
return 0; return { 0, output_ss.str() };
}
int wmain(int argc, wchar_t* argv[])
{
winrt::init_apartment();
auto result = run_command(argc, argv);
std::wcout << result.output;
return result.exit_code;
} }