Update Shell.

This commit is contained in:
Bruce
2025-11-20 09:17:32 +08:00
parent ce5d3af63b
commit 1674f2c35b
87 changed files with 85481 additions and 52 deletions
+161
View File
@@ -0,0 +1,161 @@
#pragma once
#include <vector>
#include <string>
#include <map>
#include <set>
#include "nstring.h"
#include "rctools.h"
#include "filepath.h"
#include "raii.h"
// 允许忽视命令行前缀。如当命令行前缀为“-”"/"时,且开启此项,则输入“-args”与"/args"和"args" 是等效的
#define CMDARG_IGNOREPREFIXS 0b001
// 允许参数后跟着值,如“/args=file”,但要求必须配置后缀,且是有效的字符
#define CMDARG_ENABLEPARAMS 0b010
// 当 CMDARG_ENABLEPARAMS 开启时允许参数为空。如 “/args=file”和"/args"都是允许的
#define CMDARG_IGNOREPARAMS 0b100
// 命令行参数
struct cmdarg
{
std::vector <std::wstring> prefixs; // 允许无前缀(长度为 0
std::vector <std::wstring> commands; // 参数(长度不能为 0,不能为空)
std::vector <std::wstring> postfixs; // 允许无后缀(长度为 0
std::wstring uniquelabel; // 唯一标识,参数名
std::wstring description; // 描述,用于生成帮助文本
DWORD flags; // 标志
};
#define CMDARG_PREFIXS_DEFAULT {L"-", L"/"}
#define CMDARG_POSTFIXS_DEFAULT {}
std::vector <cmdarg> g_argslist = {
{CMDARG_PREFIXS_DEFAULT, {L"silent", L"quiet", L"passive"}, CMDARG_POSTFIXS_DEFAULT, L"silent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
{CMDARG_PREFIXS_DEFAULT, {L"verysilent", L"veryquiet"}, CMDARG_POSTFIXS_DEFAULT, L"verysilent", GetRCStringSW (0), CMDARG_IGNOREPREFIXS},
{CMDARG_PREFIXS_DEFAULT, {L"multiple", L"filelist"}, {L"="}, L"multiple", GetRCStringSW (0), CMDARG_IGNOREPREFIXS | CMDARG_ENABLEPARAMS}
};
bool IsFile (const std::wstring &path)
{
return IsPathExists (path);
}
bool IsURI (const std::wstring &str)
{
try
{
auto uristr = gcnew System::String (str.c_str ());
auto uri = gcnew System::Uri (uristr);
return uri != nullptr;
}
catch (...) { return false; }
}
enum class paramtype
{
string,
file,
uri
};
struct cmdkey
{
std::wnstring key; // 键
paramtype type; // 键类型,当传入的参数是存在的文件路径时(如“C:\1.txt”)则键的类型为文件。同理也可设置为 uri
operator std::wnstring () { return key; }
operator LPCWSTR () { return key.c_str (); }
cmdkey (const std::wstring &k): key (k)
{
if (IsFile (k)) type = paramtype::file;
else if (IsURI (k)) type = paramtype::uri;
else type = paramtype::string;
}
cmdkey (const std::wstring &k, paramtype pt): key (k), type (pt) {}
bool operator == (const cmdkey &r) const { return key == r.key; }
bool operator > (const cmdkey &r) const { return key > r.key; }
bool operator < (const cmdkey &r) const { return key < r.key; }
};
struct cmdvalue
{
std::wstring value; // 值
paramtype type;
bool isnull; // 当参数不支持跟着值时,或允许时值为空时设置为真。
};
// 对于从命令行获取到的 argv 和 argc,argc 最小为 1,argv 的第一个元素指向程序。所以 startpos 为 1。
void ParseCmdArgs (LPWSTR *argv, DWORD argc, std::map <cmdkey, cmdvalue> &parseresult, DWORD startpos = 1)
{
for (size_t i = startpos; i < argc; i ++)
{
std::wnstring arg = argv [i];
arg = arg.trim ();
if (IsFile (arg)) parseresult [cmdkey (arg, paramtype::file)] = cmdvalue {L"", paramtype::file, true};
else if (IsURI (arg)) parseresult [cmdkey (arg, paramtype::uri)] = cmdvalue {L"", paramtype::uri, true};
else
{
for (auto &it : g_argslist)
{
std::set <std::wnstring> prefixs;
for (auto &it_s : it.prefixs) prefixs.insert (it_s);
int cmdhead = -1;
for (auto &it_s : prefixs)
{
auto plen = GetNormalizeStringLength (it_s);
auto parg = GetStringLeft (arg, plen);
if (it_s == parg) { cmdhead = plen; break; }
}
if (((it.flags & CMDARG_IGNOREPREFIXS) || !it.prefixs.size () || !prefixs.size ()) && cmdhead < 0)
{
if (!arg.length ()) continue;
cmdhead = 0;
}
if (cmdhead < 0) continue;
int postfixhead = -1;
std::set <std::wnstring> commands;
for (auto &it_s : it.commands) if (GetNormalizeStringLength (it_s)) commands.insert (it_s);
if (commands.empty ()) continue;
for (auto &it_s : commands)
{
auto clen = it_s.length ();
auto carg = GetStringLeft (arg.substr (cmdhead), clen);
if (it_s == carg) { postfixhead = cmdhead + clen; }
}
if (postfixhead < 0) continue;
std::set <std::wnstring> postfixs;
for (auto &it_s : it.postfixs) if (GetNormalizeStringLength (it_s)) postfixs.insert (it_s);
if (!(it.flags & CMDARG_ENABLEPARAMS)) it.postfixs.clear ();
if ((it.flags & CMDARG_ENABLEPARAMS) && postfixs.size ())
{
int valuehead = -1;
auto rightpart = StringTrim (GetStringRight (arg, lstrlenW (arg.c_str ()) - postfixhead));
if (it.flags & CMDARG_IGNOREPARAMS)
{
if (!rightpart.length ()) { parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true}; break; }
}
for (auto &it_s : postfixs)
{
auto plen = it_s.length ();
auto parg = GetStringLeft (rightpart, plen);
if (it_s == parg) { valuehead = plen; break; }
}
if (valuehead < 0) continue;
else
{
auto value = rightpart.substr (valuehead);
paramtype ptype = paramtype::string;
if (IsFile (value)) ptype = paramtype::file;
else if (IsURI (StringTrim (value))) ptype = paramtype::uri;
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {value, ptype, false};
}
break;
}
else
{
parseresult [cmdkey (it.uniquelabel, paramtype::string)] = cmdvalue {L"", paramtype::string, true};
break;
}
}
}
}
}
void ParseCmdLine (LPCWSTR lpCommandLine, std::map <cmdkey, cmdvalue> &parseresult)
{
int argc = 0;
LPWSTR *alpstr = CommandLineToArgvW (lpCommandLine, &argc);
destruct relt ([&alpstr] () {
if (alpstr) LocalFree (alpstr);
});
ParseCmdArgs (alpstr, argc, parseresult, 0);
}