From 01ff53f4dcb9e799d442a0131d8a634fc0d2c3f2 Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 6 Jun 2018 21:41:02 +0800 Subject: [PATCH 01/46] fix #24. add exclusion_id support --- CommandTrayHost/configure.cpp | 20 +++++++++++++++++++- CommandTrayHost/configure.h | 2 +- README.md | 2 ++ README.zh-cn.md | 2 ++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index ad21918..9a9a66a 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -129,6 +129,7 @@ bool initial_configure() "not_host_by_commandtrayhost": false, // 如果设置成了true,那么CommandTrayHost就不会监控它的运行了 "not_monitor_by_commandtrayhost": false, // 如果设置成true同上,但是会随着CommandTrayHost退出而关闭。 "kill_timeout": 200, // 执行关闭操作时,先尝试通知程序自己关闭然后等多少ms,然后再杀进程,默认是200ms + "exclusion_id": 1, // 互斥id,要求是大于0的整数。相同的互斥id启动时,会先杀掉其他。 }, { "name": "cmd例子2", @@ -150,6 +151,7 @@ bool initial_configure() "log_level": 0, // log级别,缺省默认为0。0为仅仅记录crontab触发记录,1附加启动时的信息,2附加下次触发的信息 "start_show": false, // 注释掉的话,使用cache值(如果有),cache禁用的状态下的默认值是false }, + "exclusion_id": 1, }, { "name": "cmd例子3", @@ -275,6 +277,7 @@ bool initial_configure() "not_host_by_commandtrayhost": false, // if true, commandtrayhost will not monitor it "not_monitor_by_commandtrayhost": false, // if true, same as above. But quit with CommandTrayHost "kill_timeout": 200, + "exclusion_id": 1, // kill all configs with same `exclusion_id` before to run current config. greater than 0. }, { "name": "cmd example 2", @@ -296,6 +299,7 @@ bool initial_configure() "log_level": 0, // log level 0 1 2 "start_show": false, // comment out to use cache }, + "exclusion_id": 1, }, { "name": "cmd example 3", @@ -930,6 +934,10 @@ rapidjson::SizeType configure_reader(std::string& out) int kill_timeout = val[name].GetInt(); return kill_timeout >= 0 && kill_timeout < static_cast((std::numeric_limits::max)()); }, }, + { "exclusion_id", iIntType, true, [](Value& val, PCSTR name)->bool { + int exclusion_id = val[name].GetInt(); + return exclusion_id > 0; + },}, }; PCSTR const global_menu[][2] = { // order is important, commandtrayhost marked word: 4bfsza3ay // with hotkey @@ -2912,6 +2920,11 @@ void disable_enable_menu(nlohmann::json& jsp, HANDLE ghJob, bool runas_admin) } else { + int exclusion_id = jsp.value("exclusion_id", 0); + if (exclusion_id > 0) + { + kill_all(false, exclusion_id); + } jsp["enabled"] = true; create_process(jsp, ghJob, runas_admin); } @@ -3238,7 +3251,8 @@ void unregisterhotkey_killtimer_all() } } -void kill_all(bool is_exit/* = true*/) + +void kill_all(bool is_exit/* = true*/, int exclusion_id) { static int volatile atomic_variable_singlton = 0; if (atomic_variable_singlton)return; @@ -3266,6 +3280,10 @@ void kill_all(bool is_exit/* = true*/) }*/ if (is_running) { + if (exclusion_id > 0 && itm.value("exclusion_id", 0) != exclusion_id) + { + continue; + } if (enable_cache && (!disable_cache_position || !disable_cache_size || !disable_cache_alpha)) { if (true == itm["en_job"]) diff --git a/CommandTrayHost/configure.h b/CommandTrayHost/configure.h index 2416931..8f3141a 100644 --- a/CommandTrayHost/configure.h +++ b/CommandTrayHost/configure.h @@ -61,7 +61,7 @@ void start_all(HANDLE, bool force = false); void restart_all(HANDLE); void update_hwnd_all(); void unregisterhotkey_killtimer_all(); -void kill_all(bool is_exit = true); +void kill_all(bool is_exit = true, int exclusion_id = 0); void left_click_toggle(); diff --git a/README.md b/README.md index c2ac1f6..d6f04a4 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ example configure "not_host_by_commandtrayhost": false, // if true, commandtrayhost will not monitor it "not_monitor_by_commandtrayhost": false, // if true, same as above. But quit with CommandTrayHost "kill_timeout": 200, // post a message to let program quit itself, if timeout killing the process + "exclusion_id": 1, // kill all configs with same `exclusion_id` before to run current config. greater than 0. }, { "name": "kcptun 1081 8.8.8.1:12346", @@ -87,6 +88,7 @@ example configure "log_level": 0, // log level 0 1 2 "start_show": false, // comment out to use cache }, + "exclusion_id": 1, }, { "name": "herokuapp", diff --git a/README.zh-cn.md b/README.zh-cn.md index 99de694..e143d98 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -71,6 +71,7 @@ Windows命令行程序运行监控系统托盘管理工具 "not_host_by_commandtrayhost": false, // 如果设置成了true,那么CommandTrayHost就不会监控它的运行了 "not_monitor_by_commandtrayhost": false, // 如果设置成true同上,但是会随着CommandTrayHost退出而关闭。 "kill_timeout": 200, // 执行关闭操作时,先尝试通知程序自己关闭然后等多少ms,然后再杀进程,默认是200ms + "exclusion_id": 1, // 互斥id,要求是大于0的整数。相同的互斥id启动时,会先杀掉其他。 }, { "name": "kcptun 1081 8.8.8.1:12346", @@ -92,6 +93,7 @@ Windows命令行程序运行监控系统托盘管理工具 "log_level": 0, // log级别,缺省默认为0。0为仅仅记录crontab触发记录,1附加启动时的信息,2附加下次触发的信息 "start_show": false, // 注释掉的话,使用cache值(如果有),cache禁用的状态下的默认值是false }, + "exclusion_id": 1, }, { "name": "herokuapp", From d7845e36634b6d49398b12e6e8d351b2d1ea4c97 Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 6 Jun 2018 21:46:40 +0800 Subject: [PATCH 02/46] 2.2.0 --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 539aa7e..1c71917 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.1-b{build} +version: 2.2-b{build} # version: 0.6-latest skip_tags: true image: Visual Studio 2017 @@ -32,7 +32,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 1 5 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 0 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 275afe557b5c1062210b02b9e8679a2e341e5990 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 11 Aug 2018 23:25:23 +0800 Subject: [PATCH 03/46] fix #28 --- CommandTrayHost/configure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index 9a9a66a..e14c73d 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2453,7 +2453,7 @@ void get_command_submenu(std::vector& outVcHmenu) if (!is_runas_admin) { AppendMenu(hSubMenu, MF_SEPARATOR, NULL, NULL); - AppendMenu(hSubMenu, MF_STRING, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + info_items_cnt + 5, + AppendMenu(hSubMenu, MF_STRING, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + info_items_cnt + 3, utf8_to_wstring((*menu_translation_pointer)[mRunAsAdministrator]).c_str() ); } From 3c2e6020f1432817b0c84b39a21699f7912476e6 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 11 Aug 2018 23:32:43 +0800 Subject: [PATCH 04/46] 2.2.1 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1c71917..5dc425b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 0 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 1 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 04ebdf17e112ee12738502767c44c53fd9822472 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 08:47:56 +0800 Subject: [PATCH 05/46] fix #30 --- CommandTrayHost/configure.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index e14c73d..78c26c6 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2185,7 +2185,10 @@ void start_all(HANDLE ghJob, bool force) if (false == ignore_all)*/ if (!i.value("ignore_all", false)) { - i["enabled"] = true; + if (!json_object_has_member(i, "exclusion_id")) + { + i["enabled"] = true; + } } } else From fe01ab9b9a7030e4417a5c2fcee8704313e15bea Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 08:50:21 +0800 Subject: [PATCH 06/46] update readme --- README.md | 4 ---- README.zh-cn.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/README.md b/README.md index d6f04a4..e91202a 100644 --- a/README.md +++ b/README.md @@ -251,10 +251,6 @@ See this file : [CommandTrayHost/CommandTrayHost/language_data.h](https://github - [ ] When restart process, keep the history standard output and standard error output in a ConsoleHelper. That's why there is a `use_builtin_console`. Maybe I have to inject some code to child process. [ConEmu](https://github.com/Maximus5/ConEmu) -- [ ] Auto update check for some github projects, etc kcptun-windows. - -- [ ] ProxyAgent,Socks5--> http,IE Proxy setting。 - - [ ] [Elevated Startup](https://stefansundin.github.io/elevatedstartup/) - [ ] UIPI (User Interface Privilege Isolation) Bypass. `ChangeWindowMessageFilterEx` diff --git a/README.zh-cn.md b/README.zh-cn.md index e143d98..7212e34 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -259,10 +259,6 @@ Windows命令行程序运行监控系统托盘管理工具 - [ ] 现在一旦重启某个应用,那么之前的窗口就会被关掉,然后重新开启一个。这样之前的日志就丢失了。希望对每个应用,启动一个独立辅助Console,即使重新启动应用,历史日志(标准IO输出)依然可以保留。 `use_builtin_console`就是用来做这个用途的。可以参考的有 [ConEmu](https://github.com/Maximus5/ConEmu),看上去必须要注入子进程,将其标准IO导入到ConsoleHelper才行。 -- [ ] 可以自动更新应用,比如kcptun-windows,提供github地址然后检测是否有更新。 - -- [ ] 内置代理转换,如Socks5--> http,IE代理快速设置。 - - [ ] 尝试集成 [Elevated Startup](https://stefansundin.github.io/elevatedstartup/) - [ ] UIPI (User Interface Privilege Isolation) Bypass. `ChangeWindowMessageFilterEx` From 7e8d94b9bf3c03e3ff130bafeb5ccbe45b621382 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 08:52:05 +0800 Subject: [PATCH 07/46] 2.2.2 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5dc425b..b30a02f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 1 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 2 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From c06e5841fdf181f4c465820a1ea7fea382ff3bd1 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 09:10:34 +0800 Subject: [PATCH 08/46] fix #30 about restart_all --- CommandTrayHost/configure.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index 78c26c6..a7923ac 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2271,8 +2271,11 @@ void restart_all(HANDLE ghJob) //#else try_read_optional_json(i, require_admin, "require_admin"); //#endif*/ - const bool require_admin = i.value("require_admin", false); - create_process(i, ghJob, require_admin); + if (!json_object_has_member(i, "exclusion_id") || i.value("enabled", false)) + { + const bool require_admin = i.value("require_admin", false); + create_process(i, ghJob, require_admin); + } } } From 7bc0e13d82a55abfb93e1467d7b87631a6700199 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 09:11:12 +0800 Subject: [PATCH 09/46] 2.2.3 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index b30a02f..242f167 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 2 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 3 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From e5f89c038b44a5176a989321eeee4dfefdcb94d7 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 09:33:18 +0800 Subject: [PATCH 10/46] update initial config.json --- CommandTrayHost/configure.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index a7923ac..a25cfd9 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -66,14 +66,14 @@ bool initial_configure() const char* config = isZHCN ? u8R"json({ /** * 0. 常见样例可以参考项目wiki. - * 1. "cmd"必须包含.exe.如果要运行批处理.bat, 可以使用 cmd.exe /c. + * 1. "cmd"必须包含.exe.如果要运行批处理.bat, 可以使用 cmd.exe /c或者cmd.exe /k. * 2. 所有的路径必须要是C:\\Windows这样的双斜杠分割,这是json的字符串规定。 * 3. 所有的路径都可以是相对路径,比如 ..\..\icons\icon.ico这种形式。 * 但是参考各有不同: * cmd里面的子程序工作路径由working_directory指定 * 其他路径则是CommandTrayHost.exe所在目录指定 * 4. 本文可以用系统自带的记事本编辑,然后保存选Unicode(大小端无所谓)或者UTF-8都可以 - * 如果用VS Code或者Sublime Text编辑,可以用JavaScript语法着色 + * 如果用VS Code或者Sublime Text编辑,可以用JSON with Comments语法着色 * 5. 多个CommandTrayHost.exe只要放到不同目录,就可以同时运行与开机启动,互相不影响. 当然了默认配置是为了演示用, * 启用了全部热键,第二个启动时会提示热键冲突,禁用或者修改第二个的热键即可。 * 6. 如果改成 "enable_cache": true ,则会将用户操作缓存到command_tray_host.cache From ab66caa4b0a0464dcefe1724de6ead8b2604135a Mon Sep 17 00:00:00 2001 From: rexdf Date: Mon, 26 Mar 2018 14:51:57 +0800 Subject: [PATCH 11/46] [nlohmann-json] update to 3.1.2 --- vcpkg_cache.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcpkg_cache.txt b/vcpkg_cache.txt index 2a3a7da..8f74e37 100644 --- a/vcpkg_cache.txt +++ b/vcpkg_cache.txt @@ -1,3 +1,5 @@ +3/26/2018 [nlohmann-json] update to 3.1.2 + 2/2/2018 [nlohmann-json] update to 3.1.0 12/31/2017 [nlohmann-json] update to 3.0.1 From 0b36e0f2c02fd13674602a22cbc8edcac9b8913a Mon Sep 17 00:00:00 2001 From: rexdf Date: Mon, 26 Mar 2018 15:41:57 +0800 Subject: [PATCH 12/46] [nlohmann-json] update to 3.1.2 --- appveyor.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 242f167..1382954 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,11 +16,13 @@ install: - cmd: >- cd /d c:\tools\vcpkg - git reset --hard + rem git reset --hard - git pull + rem git clean -ffdx - bootstrap-vcpkg.bat + rem git pull + + rem bootstrap-vcpkg.bat cd /d c:\projects\CommandTrayHost From 8bcbe6b290063a7cc09b6b098fa848a6c5d5e983 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 09:53:06 +0800 Subject: [PATCH 13/46] [nlohmann-json] update to 3.2.0 --- vcpkg_cache.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vcpkg_cache.txt b/vcpkg_cache.txt index 8f74e37..be6e748 100644 --- a/vcpkg_cache.txt +++ b/vcpkg_cache.txt @@ -1,3 +1,5 @@ +8/30/2018 [nlohmann-json] update to 3.2.0 + 3/26/2018 [nlohmann-json] update to 3.1.2 2/2/2018 [nlohmann-json] update to 3.1.0 From 261caa5b4b04bc1fc49d93f91b9751accbcea620 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 09:54:03 +0800 Subject: [PATCH 14/46] add cmd_menu_max_length doc --- CommandTrayHost/configure.cpp | 2 ++ README.md | 1 + README.zh-cn.md | 1 + 3 files changed, 4 insertions(+) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index a25cfd9..f5e1856 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -169,6 +169,7 @@ bool initial_configure() "require_admin": false, // 是否让CommandTrayHost运行时弹出UAC对自身提权 "icon": "", // 托盘图标路径,只支持ico文件,可以是多尺寸的ico; 空为内置图标 "icon_size": 256, // 图标尺寸 可以用值有256 32 16 + "cmd_menu_max_length": 0, // cmd和path最大字符串个数,0表示不限制,大于0整数表示超过之后用...标出 "lang": "auto", // zh-CN en-US https://msdn.microsoft.com/en-us/library/cc233982.aspx "groups": [ // groups的值是一个数组(方括号),可以有两种类型,一种为数值,一种为object(花括号)。object代表下级菜单。最多可以40层嵌套。object必须有name字段 { @@ -317,6 +318,7 @@ bool initial_configure() "require_admin": false, // To Run CommandTrayHost runas privileged "icon": "", // icon path, empty for default "icon_size": 256, // icon size, valid value: 256 32 16 + "cmd_menu_max_length": 0, // maximium character limit for cmd and path item in menu. 0 infinite "lang": "auto", // zh-CN en-US etc https://msdn.microsoft.com/en-us/library/cc233982.aspx "groups": [ // groups is an array. Allow element is object and number. { diff --git a/README.md b/README.md index e91202a..244cdc3 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ example configure "icon": "E:\\icons\\Mahm0udwally-All-Flat-Computer.ico", // Customize Tray Icon path // when empty, builtin default icon will be used. 256x256 "icon_size": 256, // 256 32 16 + "cmd_menu_max_length": 0, // maximium character limit for cmd and path item in menu. 0 infinite "lang": "auto", // zh-CN en-US etc https://msdn.microsoft.com/en-us/library/cc233982.aspx "groups": [ // groups is an array. Allowed element types are object and number. { diff --git a/README.zh-cn.md b/README.zh-cn.md index 7212e34..66eb6f9 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -153,6 +153,7 @@ Windows命令行程序运行监控系统托盘管理工具 // 绝大部分情况不需要admin的,但是如果真的需要,自动启动应该会有问题,可以参考使用 https://stefansundin.github.io/elevatedstartup/ "icon": "E:\\icons\\Mahm0udwally-All-Flat-Computer.ico", // 自定义托盘图标路径,空为默认内置 256x256 "icon_size": 256, // 256 32 16 + "cmd_menu_max_length": 0, // cmd和path最大字符串个数,0表示不限制,大于0整数表示超过之后用...标出 "lang": "auto", // zh-CN en-US https://msdn.microsoft.com/en-us/library/cc233982.aspx "groups": [ // groups的值是一个数组,可以有两种类型,一种为数值,一种为object。object代表下级菜单。object必须有name字段 { From 997b89fa8901fbda30ddee30519866b3f63e0622 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 12:01:49 +0800 Subject: [PATCH 15/46] implement cmd_menu_max_length --- CommandTrayHost/configure.cpp | 13 +++++++++++-- CommandTrayHost/utils.cpp | 17 +++++++++++++++++ CommandTrayHost/utils.hpp | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index f5e1856..ec1beaa 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -1280,6 +1280,14 @@ rapidjson::SizeType configure_reader(std::string& out) } return true; } }, + { "cmd_menu_max_length", iIntType, true, [](const Value& val,PCSTR name)->bool { + int cmd_menu_max_length = val[name].GetInt(); + if (cmd_menu_max_length < 0) + { + return false; + } + return true; + } }, { "enable_cache", iBoolType, true, lambda_cache_option, lambda_cache_option_value_pointer_idx }, { "conform_cache_expire", iBoolType, true, lambda_cache_option, lambda_cache_option_value_pointer_idx }, @@ -2342,6 +2350,7 @@ void get_command_submenu(std::vector& outVcHmenu) hSubMenu = CreatePopupMenu(); outVcHmenu.push_back(hSubMenu); } + int cmd_menu_max_length = global_stat.value("cmd_menu_max_length", 0); int i = 0; //std::wstring local_wstring; for (auto& itm : (*global_configs_pointer)) @@ -2393,9 +2402,9 @@ void get_command_submenu(std::vector& outVcHmenu) uSubFlags |= MF_CHECKED; } AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 0, - utf8_to_wstring(itm["path"]).c_str()); + utf8_to_wstring(truncate(itm["path"], cmd_menu_max_length)).c_str()); AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 1, - utf8_to_wstring(itm["cmd"]).c_str()); + utf8_to_wstring(truncate(itm["cmd"], cmd_menu_max_length)).c_str()); //AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 2, //utf8_to_wstring(itm["working_directory"]).c_str()); AppendMenu(hSubMenu, MF_SEPARATOR, NULL, NULL); diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index c3f0616..68b295c 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -30,6 +30,23 @@ std::wstring s2ws(const std::string& s) } #endif +std::string truncate(std::string str, size_t width, bool show_ellipsis) +{ + if (width > 0 && str.length() > width) + { + if (show_ellipsis) + { + return str.substr(0, width) + "..."; + } + else + { + return str.substr(0, width); + } + } + + return str; +} + // convert UTF-8 string to wstring std::wstring utf8_to_wstring(const std::string& str) { diff --git a/CommandTrayHost/utils.hpp b/CommandTrayHost/utils.hpp index 1c0a91c..284d2bb 100644 --- a/CommandTrayHost/utils.hpp +++ b/CommandTrayHost/utils.hpp @@ -1,5 +1,6 @@ #pragma once +std::string truncate(std::string str, size_t width, bool show_ellipsis = true); std::wstring utf8_to_wstring(const std::string&); std::string wstring_to_utf8(const std::wstring&); From 139a9fda64e4cee141713d114976a1006d8d77cb Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 14:45:02 +0800 Subject: [PATCH 16/46] Per Monitor V2 DPI awareness --- CommandTrayHost/CommandTrayHost.exe.manifest | 11 ++++++++++ CommandTrayHost/CommandTrayHost.vcxproj | 22 ++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 CommandTrayHost/CommandTrayHost.exe.manifest diff --git a/CommandTrayHost/CommandTrayHost.exe.manifest b/CommandTrayHost/CommandTrayHost.exe.manifest new file mode 100644 index 0000000..c2b6035 --- /dev/null +++ b/CommandTrayHost/CommandTrayHost.exe.manifest @@ -0,0 +1,11 @@ + + + + + PerMonitorV2,PerMonitor + + + true + + + \ No newline at end of file diff --git a/CommandTrayHost/CommandTrayHost.vcxproj b/CommandTrayHost/CommandTrayHost.vcxproj index 14da15d..3ec4b2a 100644 --- a/CommandTrayHost/CommandTrayHost.vcxproj +++ b/CommandTrayHost/CommandTrayHost.vcxproj @@ -132,6 +132,12 @@ Windows true + + $(TargetName)$(TargetExt).manifest + + + PerMonitorHighDPIAware + @@ -147,6 +153,10 @@ Windows true + + $(TargetName)$(TargetExt).manifest + PerMonitorHighDPIAware + @@ -166,6 +176,12 @@ true false + + $(TargetName)$(TargetExt).manifest + + + PerMonitorHighDPIAware + @@ -204,6 +220,12 @@ true false + + $(TargetName)$(TargetExt).manifest + + + PerMonitorHighDPIAware + From 39360eabb5250bca948429987968352a0a663e14 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 14:45:55 +0800 Subject: [PATCH 17/46] 2.2.4 --- appveyor.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 1382954..843c641 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,13 +16,13 @@ install: - cmd: >- cd /d c:\tools\vcpkg - rem git reset --hard + git reset --hard - rem git clean -ffdx + git clean -ffdx - rem git pull + git pull - rem bootstrap-vcpkg.bat + bootstrap-vcpkg.bat cd /d c:\projects\CommandTrayHost @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 3 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 4 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 2fdaf0719a4c6106f3a92fbe1b528d788a44b9b9 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 17:19:36 +0800 Subject: [PATCH 18/46] :bug: fix issue involving About Messagebox text chopped --- CommandTrayHost/CommandTrayHost.cpp | 6 +++--- CommandTrayHost/utils.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CommandTrayHost/CommandTrayHost.cpp b/CommandTrayHost/CommandTrayHost.cpp index 1b0c178..83f87f4 100644 --- a/CommandTrayHost/CommandTrayHost.cpp +++ b/CommandTrayHost/CommandTrayHost.cpp @@ -942,10 +942,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) else if (nID == WM_TASKBARNOTIFY_MENUITEM_ABOUT) { PCWSTR msg = (isZHCN) ? - (L"CommandTrayHost\n\n" L"版本: " VERSION_NUMS L"\n\n作者: rexdf" L"\n\n编译时间: " BUILD_TIME_CN) : - (L"CommandTrayHost\n\n" L"Version: " VERSION_NUMS L"\n\nAuthor: rexdf" L"\n\nBuild Timestamp: " BUILD_TIME_EN); + (L"CommandTrayHost\n\n" L"版本: " VERSION_NUMS L"\n\n作者: rexdf" L"\n\n编译时间: " BUILD_TIME_CN "\n\n") : + (L"CommandTrayHost\n\n" L"Version: " VERSION_NUMS L"\n\nAuthor: rexdf" L"\n\nBuild Timestamp: " BUILD_TIME_EN "\n\n"); - MessageBox(hWnd, msg, isZHCN ? L"关于" : utf8_to_wstring(translate("About")).c_str(), 0); + MessageBox(hWnd, msg, isZHCN ? L"关于" : utf8_to_wstring(translate("About")).c_str(), MB_TOPMOST | MB_SETFOREGROUND); } else if (nID == WM_TASKBARNOTIFY_MENUITEM_HIDEALL) { diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 68b295c..acde8be 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -362,7 +362,7 @@ int msg_prompt( { extern HWND hWnd; SetForegroundWindow(hWnd); - return MessageBox(hWnd, lpText, lpCaption, uType); + return MessageBox(hWnd, lpText, lpCaption, uType | MB_TOPMOST | MB_SETFOREGROUND); } BOOL get_hicon(PCWSTR filename, int icon_size, HICON& hIcon, bool share) From 867fedf31431f27c8bfd75de6429facb24a8232f Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 30 Aug 2018 17:20:08 +0800 Subject: [PATCH 19/46] 2.2.5 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 843c641..72a4771 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 4 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 5 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From d903fa1d9722bff7e0ffdb0570876dc0343e07ee Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 1 Sep 2018 22:25:51 +0800 Subject: [PATCH 20/46] :package: update upx from v3.94 to v3.95 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 72a4771..f57b022 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -55,7 +55,7 @@ after_build: copy XP-Release\CommandTrayHost.exe CommandTrayHost-xp-x86\ - curl -L -o upx.zip https://github.com/upx/upx/releases/download/v3.94/upx394w.zip + curl -L -o upx.zip https://github.com/upx/upx/releases/download/v3.95/upx-3.95-win64.zip 7z e upx.zip *.exe -r From fbff04e077866c251a37c91b1623d9fd19e525e8 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 20 Sep 2018 21:23:58 +0800 Subject: [PATCH 21/46] :pencil2: fix typo --- CommandTrayHost/configure.cpp | 4 ++-- README.md | 4 ++-- README.zh-cn.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index ec1beaa..b257e1c 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -81,7 +81,7 @@ bool initial_configure() * CommandTrayHost.exe时,会忽略config.json里面的值。 * 缓存失效判定是与config.json之间的时间戳先后对比。缓存写入磁盘只会在全部操作(全部启用 * 全部禁用,全部显示隐藏),以及退出时发现缓存发生有效更改时才会写入磁盘。 - * 7. 全局热键格式: 可以使用alt win shit ctrl的任意个组合加上一个按键 + * 7. 全局热键格式: 可以使用alt win shift ctrl的任意个组合加上一个按键 * 加上的按键支持0-9的数字 A-Z的字母,其他特殊按钮,鼠标左右键,滚轮,甚至手柄按钮也是可以的.比如上方向键0x26 * 键盘码参考这里 https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx * 大小写无关,顺序无关,如果多个非修饰符的按钮,最后的那个按钮会起作用。 @@ -239,7 +239,7 @@ bool initial_configure() * 4. Relative path base is where CommandTrayHost.exe is started. * 5. CommandTrayHost.exe in different directories can run at same time. * 6. set "enable_cache": true to enable cache. - * 7. alt win shit ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" + * 7. alt win shift ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" * https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx * 8. crontab is from https://github.com/staticlibs/ccronexpr */ diff --git a/README.md b/README.md index 244cdc3..56cea96 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ example configure "icon": "", // icon for console windows "alpha": 170, // alpha for console windows, 0-255 integer "topmost": false, // topmost for console windows - // alt win shit ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" + // alt win shift ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx "hotkey": { // you don't nedd to set up all "disable_enable": "Shift+Win+D", // disable/enable toggle @@ -186,7 +186,7 @@ example configure "disable_cache_enabled": true, "disable_cache_show": false, "disable_cache_alpha": false, // (only work for configs with alpha) - // alt win shit ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" + // alt win shift ctrl 0-9 A-Z, seperated by space or +. You can also use "ALT+WIN+CTRL+0x20" // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx "hotkey": { "disable_all": "Alt+Win+Shift+D", diff --git a/README.zh-cn.md b/README.zh-cn.md index 66eb6f9..4cee978 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -59,7 +59,7 @@ Windows命令行程序运行监控系统托盘管理工具 "icon": "", // 命令行窗口的图标 "alpha": 170, // 命令行窗口的透明度,0-255之间的整数,0为完全看不见,255完全不透明 "topmost": false, // 命令行窗口置顶 - // 可以使用的有alt win shit ctrl 0-9 A-Z 空格或者+号分割 + // 可以使用的有alt win shift ctrl 0-9 A-Z 空格或者+号分割 // 或者使用这种形式 "ALT+WIN+CTRL+0x20" 鼠标手柄的键盘码参考 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx "hotkey": { // 下面并不需要都出现,可以只设置部分 @@ -190,7 +190,7 @@ Windows命令行程序运行监控系统托盘管理工具 "disable_cache_enabled": true, // 禁止缓存启用禁用状态 "disable_cache_show": false, // 禁止缓存显示隐藏状态 "disable_cache_alpha": false, // 禁止缓存透明度 (缓存时只对有alpha值的configs有作用) - // 可以使用的有alt win shit ctrl 0-9 A-Z 空格或者+号分割 + // 可以使用的有alt win shift ctrl 0-9 A-Z 空格或者+号分割 // 或者使用这种形式 "ALT+WIN+CTRL+0x20" 鼠标手柄的键盘码参考 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx "hotkey": { From d447f3d1c9e10dcb4d33b63773bf8a961cef92f2 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 20 Sep 2018 23:33:33 +0800 Subject: [PATCH 22/46] :sparkles: add kill_process_tree, fix #31 --- CommandTrayHost/configure.cpp | 24 +++++--- CommandTrayHost/stdafx.h | 3 + CommandTrayHost/utils.cpp | 113 +++++++++++++++++++++++++++++++--- CommandTrayHost/utils.hpp | 4 +- README.md | 1 + README.zh-cn.md | 3 +- 6 files changed, 127 insertions(+), 21 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index b257e1c..d32cb76 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -130,6 +130,7 @@ bool initial_configure() "not_monitor_by_commandtrayhost": false, // 如果设置成true同上,但是会随着CommandTrayHost退出而关闭。 "kill_timeout": 200, // 执行关闭操作时,先尝试通知程序自己关闭然后等多少ms,然后再杀进程,默认是200ms "exclusion_id": 1, // 互斥id,要求是大于0的整数。相同的互斥id启动时,会先杀掉其他。 + "kill_process_tree": false, // 杀进程的时候同时杀掉其子进程,用于nginx. 为true时,kill_timeout无效 }, { "name": "cmd例子2", @@ -279,6 +280,7 @@ bool initial_configure() "not_monitor_by_commandtrayhost": false, // if true, same as above. But quit with CommandTrayHost "kill_timeout": 200, "exclusion_id": 1, // kill all configs with same `exclusion_id` before to run current config. greater than 0. + "kill_process_tree": false, // kill all child process tree,for nginx }, { "name": "cmd example 2", @@ -845,11 +847,12 @@ rapidjson::SizeType configure_reader(std::string& out) int64_t handle = (*_global_config_i_ref)["handle"]; int64_t pid = (*_global_config_i_ref)["pid"]; DWORD timeout = _global_config_i_ref->value("kill_timeout", 200); + bool kill_process_tree = _global_config_i_ref->value("kill_process_tree", false); #ifdef _DEBUG std::string name_A = (*_global_config_i_ref)["name"]; - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name_A).c_str(), false); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name_A).c_str(), kill_process_tree, false); #else - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, false); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, kill_process_tree, false); #endif config_i_unchanged = false; } @@ -940,6 +943,7 @@ rapidjson::SizeType configure_reader(std::string& out) int exclusion_id = val[name].GetInt(); return exclusion_id > 0; },}, + { "kill_process_tree", iBoolType, true, nullptr, }, }; PCSTR const global_menu[][2] = { // order is important, commandtrayhost marked word: 4bfsza3ay // with hotkey @@ -2554,11 +2558,12 @@ void create_process( LOGMESSAGE(L"pid:%d process running, now kill it\n", pid); DWORD timeout = jsp.value("kill_timeout", 200); + bool kill_process_tree = jsp.value("kill_process_tree", false); #ifdef _DEBUG std::string name_A = jsp["name"]; - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name_A).c_str(), false); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name_A).c_str(), kill_process_tree, false); #else - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, false); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, kill_process_tree, false); #endif } @@ -2919,11 +2924,12 @@ void disable_enable_menu(nlohmann::json& jsp, HANDLE ghJob, bool runas_admin) LOGMESSAGE(L"pid:%d disable_menu process running, now kill it\n", pid); DWORD timeout = jsp.value("kill_timeout", 200); + bool kill_process_tree = jsp.value("kill_process_tree", false); #ifdef _DEBUG std::string name = jsp["name"]; - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name).c_str()); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name).c_str(), kill_process_tree); #else - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, kill_process_tree); #endif } jsp["handle"] = 0; @@ -3333,11 +3339,13 @@ void kill_all(bool is_exit/* = true*/, int exclusion_id) LOGMESSAGE(L"pid:%d process running, now kill it\n", pid); DWORD timeout = itm.value("kill_timeout", 200); + bool kill_process_tree = itm.value("kill_process_tree", false); #ifdef _DEBUG const std::string name = itm["name"]; - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name).c_str(), !is_exit); + + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, utf8_to_wstring(name).c_str(), kill_process_tree, !is_exit); #else - check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, !is_exit); + check_and_kill(reinterpret_cast(handle), static_cast(pid), timeout, kill_process_tree, !is_exit); #endif if (is_exit == false) { diff --git a/CommandTrayHost/stdafx.h b/CommandTrayHost/stdafx.h index 42a0d44..b20885b 100644 --- a/CommandTrayHost/stdafx.h +++ b/CommandTrayHost/stdafx.h @@ -33,6 +33,9 @@ #include // CComPtr #include +#ifdef _DEBUG_PROCESS_TREE +#include +#endif #include #include diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index acde8be..4c67042 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -597,27 +597,120 @@ extern bool is_cache_valid; //extern BOOL isZHCN, isENUS; +#ifdef _DEBUG_PROCESS_TREE +// not working for nginx continuous fork #ifdef _DEBUG -void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, PCWSTR name, bool is_update_cache) +bool kill_child_tree(int dep, DWORD pid, DWORD timeout, PCWSTR name) #else -void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, bool is_update_cache) +bool kill_child_tree(int dep, DWORD pid, DWORD timeout) +#endif +{ + LOGMESSAGE(L"kill_child_tree running %s PID=%d", name, pid); + PROCESSENTRY32 pe; + + memset(&pe, 0, sizeof(PROCESSENTRY32)); + pe.dwSize = sizeof(PROCESSENTRY32); + + HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (::Process32First(hSnap, &pe)) + { + BOOL bContinue = TRUE; + + // kill child processes + while (bContinue) + { + // only kill child processes + if (pe.th32ParentProcessID == pid) + { + LOGMESSAGE(L"dep:%d found child pid PID=%d", dep, pe.th32ProcessID); + +#ifdef _DEBUG + kill_child_tree(dep + 1, pe.th32ProcessID, timeout, name); +#else + kill_child_tree(dep + 1, pe.th32ProcessID, timeout); +#endif + + /*if (TA_FAILED == TerminateApp(pe.th32ProcessID, timeout)) + { + LOGMESSAGE(L"TerminateApp %s pid: %d failed!! File = %S Line = %d Func=%S Date=%S Time=%S\n", + name, pid, + __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); + //TerminateProcess(pe.th32ProcessID, 0); + HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); + + if (hChildProc) + { + ::TerminateProcess(hChildProc, 1); + ::CloseHandle(hChildProc); + } + }*/ + } + + bContinue = ::Process32Next(hSnap, &pe); + } + + // kill the main process + if (dep > 0) + { + LOGMESSAGE(L"killing pid PID=%d", pid); + if (TA_FAILED == TerminateApp(pid, timeout)) + { + LOGMESSAGE(L"TerminateApp %s pid: %d failed!! File = %S Line = %d Func=%S Date=%S Time=%S\n", + name, pid, + __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); + HANDLE hChildProc = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + + if (hChildProc) + { + ::TerminateProcess(hChildProc, 1); + ::CloseHandle(hChildProc); + } + } + } + return true; + } + return false; +} + +#endif + +#ifdef _DEBUG +void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, PCWSTR name, bool kill_process_tree, bool is_update_cache) +#else +void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, bool kill_process_tree, bool is_update_cache) #endif { assert(GetProcessId(hProcess) == pid); if (GetProcessId(hProcess) == pid) { - if (TA_FAILED == TerminateApp(pid, timeout)) + if (kill_process_tree) { - LOGMESSAGE(L"TerminateApp %s pid: %d failed!! File = %S Line = %d Func=%S Date=%S Time=%S\n", - name, pid, - __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); - TerminateProcess(hProcess, 0); + std::wstring system_cmd = L"TASKKILL /F /T /PID " + std::to_wstring(pid); + _wsystem(system_cmd.c_str()); +#ifdef _DEBUG_PROCESS_TREE +#ifdef _DEBUG + kill_child_tree(0, pid, timeout, name); +#else + kill_child_tree(0, pid, timeout); +#endif +#endif } else { - LOGMESSAGE(L"TerminateApp %S pid: %d successed. File = %S Line = %d Func=%S Date=%S Time=%S\n", - name, pid, - __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); + if (TA_FAILED == TerminateApp(pid, timeout)) + { + LOGMESSAGE(L"TerminateApp %s pid: %d failed!! File = %S Line = %d Func=%S Date=%S Time=%S\n", + name, pid, + __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); + TerminateProcess(hProcess, 0); + } + else + { + LOGMESSAGE(L"TerminateApp %S pid: %d successed. File = %S Line = %d Func=%S Date=%S Time=%S\n", + name, pid, + __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__); + } } CloseHandle(hProcess); } diff --git a/CommandTrayHost/utils.hpp b/CommandTrayHost/utils.hpp index 284d2bb..0f0281a 100644 --- a/CommandTrayHost/utils.hpp +++ b/CommandTrayHost/utils.hpp @@ -65,9 +65,9 @@ int get_caption_from_hwnd(HWND hwnd, std::wstring& caption); BOOL is_hwnd_valid_caption(HWND hwnd, PCWSTR caption_, DWORD pid_); #ifdef _DEBUG -void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, PCWSTR name, bool is_update_cache = true); +void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, PCWSTR name,bool kill_process_tree, bool is_update_cache = true); #else -void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout, bool is_update_cache = true); +void check_and_kill(HANDLE hProcess, DWORD pid, DWORD timeout,bool kill_process_tree, bool is_update_cache = true); #endif int msg_prompt( diff --git a/README.md b/README.md index 56cea96..69bee4e 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ example configure "not_monitor_by_commandtrayhost": false, // if true, same as above. But quit with CommandTrayHost "kill_timeout": 200, // post a message to let program quit itself, if timeout killing the process "exclusion_id": 1, // kill all configs with same `exclusion_id` before to run current config. greater than 0. + "kill_process_tree": false, // kill all child process tree,for nginx }, { "name": "kcptun 1081 8.8.8.1:12346", diff --git a/README.zh-cn.md b/README.zh-cn.md index 4cee978..8450e13 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -71,7 +71,8 @@ Windows命令行程序运行监控系统托盘管理工具 "not_host_by_commandtrayhost": false, // 如果设置成了true,那么CommandTrayHost就不会监控它的运行了 "not_monitor_by_commandtrayhost": false, // 如果设置成true同上,但是会随着CommandTrayHost退出而关闭。 "kill_timeout": 200, // 执行关闭操作时,先尝试通知程序自己关闭然后等多少ms,然后再杀进程,默认是200ms - "exclusion_id": 1, // 互斥id,要求是大于0的整数。相同的互斥id启动时,会先杀掉其他。 + "exclusion_id": 1, // 互斥id,要求是大于0的整数。相同的互斥id启动时,会先杀掉其他 + "kill_process_tree": false, // 杀进程的时候同时杀掉其子进程,用于nginx. 为true时,kill_timeout无效 }, { "name": "kcptun 1081 8.8.8.1:12346", From cf83812d79ae1b43bbf8df9729136c68e75322f1 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 20 Sep 2018 23:41:42 +0800 Subject: [PATCH 23/46] :bookmark: 2.2.6 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f57b022..eb6c783 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 5 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 6 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From af2d4f6d2569121f755009dc034837713617cea5 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 13 Dec 2018 01:55:26 +0800 Subject: [PATCH 24/46] fix #34 --- CommandTrayHost/configure.cpp | 4 ++++ CommandTrayHost/utils.cpp | 15 +++++++++++++++ CommandTrayHost/utils.hpp | 2 ++ 3 files changed, 21 insertions(+) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index d32cb76..c3df606 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -1919,6 +1919,7 @@ int init_global(HANDLE& ghJob, HICON& hIcon) i["en_job"] = false; } std::wstring cmd = utf8_to_wstring(i["cmd"]), path = utf8_to_wstring(i["path"]); + path = get_abs_path(path, cmd); TCHAR commandLine[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 if (NULL != PathCombine(commandLine, path.c_str(), cmd.c_str())) { @@ -2516,6 +2517,9 @@ void create_process( std::wstring cmd_wstring = utf8_to_wstring(jsp["cmd"]); std::wstring path_wstring = utf8_to_wstring(jsp["path"]); std::wstring working_directory_wstring = utf8_to_wstring(jsp["working_directory"]); + + path_wstring = get_abs_path(path_wstring, cmd_wstring); + LPCTSTR cmd = cmd_wstring.c_str(); LPCTSTR path = path_wstring.c_str(); //LPCTSTR working_directory = working_directory_wstring.c_str(); diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 4c67042..f5ca97f 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -61,6 +61,21 @@ std::string wstring_to_utf8(const std::wstring& str) return myconv.to_bytes(str); } +extern TCHAR szPathToExeDir[MAX_PATH * 10]; + +std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { + if (path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && cmd_wstring.compare(0, 2, L".."))) { + TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 + if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(/*NULL, */L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + } + return abs_path; + } + return path_wstring; +} + /* // convert UTF-8 string to u16string std::u16string utf8_to_u16string(const std::string& str) diff --git a/CommandTrayHost/utils.hpp b/CommandTrayHost/utils.hpp index 0f0281a..06f923f 100644 --- a/CommandTrayHost/utils.hpp +++ b/CommandTrayHost/utils.hpp @@ -4,6 +4,8 @@ std::string truncate(std::string str, size_t width, bool show_ellipsis = true); std::wstring utf8_to_wstring(const std::string&); std::string wstring_to_utf8(const std::wstring&); +std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring); + bool printf_to_bufferA(char* dst, size_t max_len, size_t& cursor, PCSTR fmt, ...); int64_t FileSize(PCWSTR); From 60f2b283342002b2d201b47f910b8abe4f470d12 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 13 Dec 2018 02:00:44 +0800 Subject: [PATCH 25/46] 2.2.7 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index eb6c783..8ceb8d1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 6 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 7 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 37f22fbbe677f642700de5a4d9c9e5807a2a5720 Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 13 Dec 2018 23:44:13 +0800 Subject: [PATCH 26/46] fix #34 --- CommandTrayHost/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index f5ca97f..412f7f8 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -64,7 +64,7 @@ std::string wstring_to_utf8(const std::wstring& str) extern TCHAR szPathToExeDir[MAX_PATH * 10]; std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { - if (path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && cmd_wstring.compare(0, 2, L".."))) { + if (0 == path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && cmd_wstring.compare(0, 2, L".."))) { TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) { From 7b7c103c9e762655af3c958cbe59deb4529d05be Mon Sep 17 00:00:00 2001 From: rexdf Date: Thu, 13 Dec 2018 23:45:53 +0800 Subject: [PATCH 27/46] 2.2.8 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8ceb8d1..c3f122f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 7 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 8 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From bcb0d42005083b47bc2f17b8fd0949d7ef4550d2 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 15 Dec 2018 20:21:45 +0800 Subject: [PATCH 28/46] fix #34 again --- CommandTrayHost/utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 412f7f8..02bd4e9 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -64,7 +64,7 @@ std::string wstring_to_utf8(const std::wstring& str) extern TCHAR szPathToExeDir[MAX_PATH * 10]; std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { - if (0 == path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && cmd_wstring.compare(0, 2, L".."))) { + if (0 == path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && 0 == cmd_wstring.compare(0, 2, L".."))) { TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) { From 4143d3a2b784385cc04d6db1ed68433f5025069c Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 15 Dec 2018 23:30:17 +0800 Subject: [PATCH 29/46] fix #36 & #34 --- .gitignore | 2 ++ CommandTrayHost/CommandTrayHost.cpp | 10 ++++++- CommandTrayHost/configure.cpp | 45 +++++++++++++++++++++++++++-- CommandTrayHost/configure.h | 2 ++ CommandTrayHost/stdafx.h | 2 ++ CommandTrayHost/utils.cpp | 22 +++++++++++++- 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 892d71e..e4b5a5a 100644 --- a/.gitignore +++ b/.gitignore @@ -264,3 +264,5 @@ __pycache__/ # Visual Studio Code .vscode/ +enc_temp_folder/ + diff --git a/CommandTrayHost/CommandTrayHost.cpp b/CommandTrayHost/CommandTrayHost.cpp index 83f87f4..c975f69 100644 --- a/CommandTrayHost/CommandTrayHost.cpp +++ b/CommandTrayHost/CommandTrayHost.cpp @@ -991,7 +991,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LOGMESSAGE(L"%x Clicked. %d %d\n", nID, menu_idx, submenu_idx); nlohmann::json& js = (*global_configs_pointer)[menu_idx]; cache_config_cursor = menu_idx; - if (submenu_idx < 3) + if (submenu_idx == 0) + { + open_path(js); + } + else if (submenu_idx == 1) + { + select_file(js); + } + else if (submenu_idx == 2) { show_hide_toggle(js); } diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index c3df606..b0f895e 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2406,9 +2406,9 @@ void get_command_submenu(std::vector& outVcHmenu) { uSubFlags |= MF_CHECKED; } - AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 0, + AppendMenu(hSubMenu, uSubFlags&(~MF_GRAYED), WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 0, utf8_to_wstring(truncate(itm["path"], cmd_menu_max_length)).c_str()); - AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 1, + AppendMenu(hSubMenu, uSubFlags&(~MF_GRAYED), WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 1, utf8_to_wstring(truncate(itm["cmd"], cmd_menu_max_length)).c_str()); //AppendMenu(hSubMenu, uSubFlags, WM_TASKBARNOTIFY_MENUITEM_COMMAND_BASE + i * 0x10 + 2, //utf8_to_wstring(itm["working_directory"]).c_str()); @@ -3113,6 +3113,47 @@ void left_click_toggle() } } +void open_path(nlohmann::json& jsp) +{ + std::wstring cmd = utf8_to_wstring(jsp["cmd"]), path = utf8_to_wstring(jsp["path"]); + path = get_abs_path(path, cmd); + ShellExecute(NULL, NULL, path.c_str(), NULL, NULL, SW_SHOWNORMAL); +} + +void select_file(nlohmann::json& jsp) +{ + std::wstring cmd = utf8_to_wstring(jsp["cmd"]), path = utf8_to_wstring(jsp["path"]); + path = get_abs_path(path, cmd); + TCHAR commandLine[MAX_PATH * 128]; + + if (NULL != PathCombine(commandLine, path.c_str(), cmd.c_str())) + { + //_wsystem((std::wstring(L"explorer /select,") + commandLine).c_str()); + if (1) + { + TCHAR commandPath[MAX_PATH * 128]; + StringCchCopy(commandPath, MAX_PATH * 128, commandLine); + PathRemoveFileSpec(commandPath); + LOGMESSAGE("!!\n%s %s", commandPath, commandLine); + HRESULT hr; + hr = CoInitializeEx(0, COINIT_MULTITHREADED); + + ITEMIDLIST* folder = ILCreateFromPath(commandPath); + std::vector v; + v.push_back(ILCreateFromPath(commandLine)); + + SHOpenFolderAndSelectItems(folder, v.size(), const_cast(v.data()), 0); + + for (auto idl : v) + { + ILFree(const_cast(idl)); + } + ILFree(folder); + if (SUCCEEDED(hr)) ::CoUninitialize(); + } + } +} + void show_hide_toggle(nlohmann::json& jsp) { if (jsp["running"] == false)return; diff --git a/CommandTrayHost/configure.h b/CommandTrayHost/configure.h index 8f3141a..18f9107 100644 --- a/CommandTrayHost/configure.h +++ b/CommandTrayHost/configure.h @@ -51,6 +51,8 @@ int init_global(HANDLE&, HICON&); void create_process(nlohmann::json& jsp, const HANDLE&, bool runas_admin = false, bool log_crontab = false); void show_hide_toggle(nlohmann::json& jsp); +void open_path(nlohmann::json& jsp); +void select_file(nlohmann::json& jsp); void disable_enable_menu(nlohmann::json& jsp, HANDLE, bool runas_admin = false); BOOL undock_window(int idx); diff --git a/CommandTrayHost/stdafx.h b/CommandTrayHost/stdafx.h index b20885b..d5ba479 100644 --- a/CommandTrayHost/stdafx.h +++ b/CommandTrayHost/stdafx.h @@ -33,6 +33,8 @@ #include // CComPtr #include +#include + #ifdef _DEBUG_PROCESS_TREE #include #endif diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 02bd4e9..e0baed4 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -63,9 +63,29 @@ std::string wstring_to_utf8(const std::wstring& str) extern TCHAR szPathToExeDir[MAX_PATH * 10]; -std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { +/*std::wstring get_abs_path_old(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { if (0 == path_wstring.compare(0, 2, L"..") || (path_wstring == L"" && 0 == cmd_wstring.compare(0, 2, L".."))) { TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 + if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + } + return abs_path; + } + return path_wstring; +}*/ + +std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) +{ + TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 + if (NULL == PathCombine(abs_path, path_wstring.c_str(), cmd_wstring.c_str())) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + } + if (NULL == StrChr(abs_path, ':')) + { if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) { LOGMESSAGE(L"Copy CTH path failed\n"); From 814589954029db8ea1c14994d882b7d701b71d73 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sat, 15 Dec 2018 23:59:50 +0800 Subject: [PATCH 30/46] fix select file cmd with parameters --- CommandTrayHost/configure.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index b0f895e..f84995a 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -3128,11 +3128,27 @@ void select_file(nlohmann::json& jsp) if (NULL != PathCombine(commandLine, path.c_str(), cmd.c_str())) { + int exe_seperator = jsp.value("exe_seperator", -1); + + /*PTSTR pIdx = StrStr(commandLine, L".exe"); + if (pIdx == NULL) + { + msg_prompt(L"cmd must contain .exe four characters", L"Warning", MB_OK | MB_ICONWARNING); + } + if (pIdx) + { + *(pIdx + 4) = 0; + } + bool file_exist = PathFileExists(commandLine);*/ + //_wsystem((std::wstring(L"explorer /select,") + commandLine).c_str()); - if (1) + if (exe_seperator >= 0) { + int str_len_exe_filename = exe_seperator + 4; + commandLine[str_len_exe_filename] = 0; + TCHAR commandPath[MAX_PATH * 128]; - StringCchCopy(commandPath, MAX_PATH * 128, commandLine); + StringCchCopy(commandPath, str_len_exe_filename + 2, commandLine); PathRemoveFileSpec(commandPath); LOGMESSAGE("!!\n%s %s", commandPath, commandLine); HRESULT hr; From 7cc419fc665d45f6aed87b5f333de58e118c6fe7 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sun, 16 Dec 2018 00:01:40 +0800 Subject: [PATCH 31/46] :bookmark: 2.2.9 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c3f122f..02d5db8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 8 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 9 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From e3ccbb46ac972d9d4150dc69412e839714ab8f35 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sun, 16 Dec 2018 00:25:59 +0800 Subject: [PATCH 32/46] fix C4090 & C4267 warning, fix logical error when : exist in parameter --- CommandTrayHost/configure.cpp | 4 ++-- CommandTrayHost/utils.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index f84995a..3fdb2c8 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -3154,11 +3154,11 @@ void select_file(nlohmann::json& jsp) HRESULT hr; hr = CoInitializeEx(0, COINIT_MULTITHREADED); - ITEMIDLIST* folder = ILCreateFromPath(commandPath); + auto folder = ILCreateFromPath(commandPath); std::vector v; v.push_back(ILCreateFromPath(commandLine)); - SHOpenFolderAndSelectItems(folder, v.size(), const_cast(v.data()), 0); + SHOpenFolderAndSelectItems(folder, static_cast(v.size()), const_cast(v.data()), 0); for (auto idl : v) { diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index e0baed4..a4141d7 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -84,7 +84,7 @@ std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& LOGMESSAGE(L"Copy CTH path failed\n"); msg_prompt(L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); } - if (NULL == StrChr(abs_path, ':')) + if (abs_path[1] != L':') // if : exist in parameter { if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) { From e94c821cdd8b22f45c7ac7eb0141adf8dd55e650 Mon Sep 17 00:00:00 2001 From: rexdf Date: Sun, 16 Dec 2018 00:29:50 +0800 Subject: [PATCH 33/46] :art: reformat --- CommandTrayHost/configure.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index 3fdb2c8..91bd747 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -3151,21 +3151,26 @@ void select_file(nlohmann::json& jsp) StringCchCopy(commandPath, str_len_exe_filename + 2, commandLine); PathRemoveFileSpec(commandPath); LOGMESSAGE("!!\n%s %s", commandPath, commandLine); - HRESULT hr; - hr = CoInitializeEx(0, COINIT_MULTITHREADED); - - auto folder = ILCreateFromPath(commandPath); - std::vector v; - v.push_back(ILCreateFromPath(commandLine)); + { + HRESULT hr; + hr = CoInitializeEx(0, COINIT_MULTITHREADED); + if (SUCCEEDED(hr)) + { + auto folder = ILCreateFromPath(commandPath); + std::vector v; + v.push_back(ILCreateFromPath(commandLine)); - SHOpenFolderAndSelectItems(folder, static_cast(v.size()), const_cast(v.data()), 0); + SHOpenFolderAndSelectItems(folder, static_cast(v.size()), + const_cast(v.data()), 0); - for (auto idl : v) - { - ILFree(const_cast(idl)); + for (auto idl : v) + { + ILFree(const_cast(idl)); + } + ILFree(folder); + CoUninitialize(); + } } - ILFree(folder); - if (SUCCEEDED(hr)) ::CoUninitialize(); } } } From fe90c6be8c2c197f0a82fc2edff0f32d24d3227f Mon Sep 17 00:00:00 2001 From: rexdf Date: Sun, 16 Dec 2018 00:30:48 +0800 Subject: [PATCH 34/46] :bookmark: 2.3.0 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 02d5db8..a72b07a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 2 9 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 0 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 972a5a5e9de4cb8e6dff987b42e324ed78cb3ab3 Mon Sep 17 00:00:00 2001 From: rexdf Date: Mon, 17 Dec 2018 23:39:27 +0800 Subject: [PATCH 35/46] fix #37 --- CommandTrayHost/configure.cpp | 2 +- CommandTrayHost/utils.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index 91bd747..61e8bb8 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2731,7 +2731,7 @@ void create_process( crontab_log(crontab_ref, 0, 0, jsp["name"].get().c_str(), buffer, __FUNCTION__, 0, 1); } - LOGMESSAGE(L"%s\n", commandLine); + LOGMESSAGE(L"%s\n%s\n", commandLine, working_directory); // https://stackoverflow.com/questions/53208/how-do-i-automatically-destroy-child-processes-in-windows // Launch child process - example is notepad.exe diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index a4141d7..6d4b096 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -93,6 +93,11 @@ std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& } return abs_path; } + else if(path_wstring == L"") + { + PathRemoveFileSpec(abs_path); + return abs_path; + } return path_wstring; } From 69ae1e3a5bf6e2d99341f87562733fe9ff82cf92 Mon Sep 17 00:00:00 2001 From: rexdf Date: Mon, 17 Dec 2018 23:42:16 +0800 Subject: [PATCH 36/46] :bookmark: 2.3.1 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a72b07a..0d5ca1e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 0 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 1 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 785b437a8c8557f7336ce0200409a69dbb0600cb Mon Sep 17 00:00:00 2001 From: rexdf Date: Mon, 17 Dec 2018 23:50:31 +0800 Subject: [PATCH 37/46] :bulb: add test case --- CommandTrayHost/utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 6d4b096..13dd92b 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -93,12 +93,12 @@ std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& } return abs_path; } - else if(path_wstring == L"") + else if(path_wstring == L"") // path: C:\windows, cmd: system32\cmd.exe { PathRemoveFileSpec(abs_path); return abs_path; } - return path_wstring; + return path_wstring; // path: C:\windows, cmd: system32\cmd.exe } /* From 176bd71ea50601bbf819394df56cde83fecc5526 Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 19 Dec 2018 01:58:28 +0800 Subject: [PATCH 38/46] :sparkles: fix #37, add support > symbol in working_directory. --- CommandTrayHost/configure.cpp | 2 ++ CommandTrayHost/utils.cpp | 58 +++++++++++++++++++++++++++++++++-- CommandTrayHost/utils.hpp | 1 + 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index 61e8bb8..a5f3c9e 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -2520,6 +2520,8 @@ void create_process( path_wstring = get_abs_path(path_wstring, cmd_wstring); + working_directory_wstring = get_abs_working_directory(path_wstring, working_directory_wstring); + LPCTSTR cmd = cmd_wstring.c_str(); LPCTSTR path = path_wstring.c_str(); //LPCTSTR working_directory = working_directory_wstring.c_str(); diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 13dd92b..4f3a217 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -76,7 +76,7 @@ extern TCHAR szPathToExeDir[MAX_PATH * 10]; return path_wstring; }*/ -std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) +/*std::wstring get_abs_path_old2(const std::wstring& path_wstring, const std::wstring& cmd_wstring) { TCHAR abs_path[MAX_PATH * 128]; // 这个必须要求是可写的字符串,不能是const的。 if (NULL == PathCombine(abs_path, path_wstring.c_str(), cmd_wstring.c_str())) @@ -89,7 +89,7 @@ std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) { LOGMESSAGE(L"Copy CTH path failed\n"); - msg_prompt(/*NULL, */L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + msg_prompt(L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); } return abs_path; } @@ -99,6 +99,60 @@ std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& return abs_path; } return path_wstring; // path: C:\windows, cmd: system32\cmd.exe +}*/ + +std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring) +{ + if (path_wstring.length() > 2 && path_wstring[1] == L':') + { + return path_wstring; + } + TCHAR abs_path[MAX_PATH * 128]; + if (path_wstring == L"" && cmd_wstring.length() > 2 && cmd_wstring[1] == L':') + { + StringCchCopy(abs_path, cmd_wstring.length() + 2, cmd_wstring.c_str()); + PathRemoveFileSpec(abs_path); + return abs_path; + } + if (NULL == PathCombine(abs_path, szPathToExeDir, path_wstring.c_str())) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(/*NULL, */L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + return L""; + } + else + { + return abs_path; + } +} + +std::wstring get_abs_working_directory(const std::wstring& path_wstring, const std::wstring& working_directory_wstring) +{ + if (working_directory_wstring.length() > 2 && working_directory_wstring[1] == L':') + { + return working_directory_wstring; + } + TCHAR abs_path[MAX_PATH * 128]; + if (working_directory_wstring.length() > 1 && working_directory_wstring[0] == L'>') + { + if (NULL == PathCombine(abs_path, szPathToExeDir, working_directory_wstring.c_str() + 1)) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(/*NULL, */L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + return L""; + } + + return abs_path; + } + + if (NULL == PathCombine(abs_path, path_wstring.c_str(), working_directory_wstring.c_str())) + { + LOGMESSAGE(L"Copy CTH path failed\n"); + msg_prompt(/*NULL, */L"PathCombine Failed", L"Error", MB_OK | MB_ICONERROR); + return L""; + } + + return abs_path; } /* diff --git a/CommandTrayHost/utils.hpp b/CommandTrayHost/utils.hpp index 06f923f..d969de7 100644 --- a/CommandTrayHost/utils.hpp +++ b/CommandTrayHost/utils.hpp @@ -5,6 +5,7 @@ std::wstring utf8_to_wstring(const std::string&); std::string wstring_to_utf8(const std::wstring&); std::wstring get_abs_path(const std::wstring& path_wstring, const std::wstring& cmd_wstring); +std::wstring get_abs_working_directory(const std::wstring& path_wstring, const std::wstring& working_directory_wstring); bool printf_to_bufferA(char* dst, size_t max_len, size_t& cursor, PCSTR fmt, ...); From a532e41e76f4913e715d8a8dc478745c3f94a59d Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 19 Dec 2018 02:00:15 +0800 Subject: [PATCH 39/46] :bookmark: 2.3.2 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 0d5ca1e..0abd59c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 1 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 2 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From a0ac18c463e29581f45c210c5aaf16fab5eb121d Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 19 Dec 2018 02:15:51 +0800 Subject: [PATCH 40/46] update zip filename version to 2.3 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 0abd59c..d9be874 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.2-b{build} +version: 2.3-b{build} # version: 0.6-latest skip_tags: true image: Visual Studio 2017 From 5345261574c43a639c61d2dbd7acb684c0940738 Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 19 Dec 2018 20:31:36 +0800 Subject: [PATCH 41/46] :bug: :bulb: fix #37, logical error & document --- CommandTrayHost/configure.cpp | 20 +++++++++++++------- CommandTrayHost/utils.cpp | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CommandTrayHost/configure.cpp b/CommandTrayHost/configure.cpp index a5f3c9e..f7aedfa 100644 --- a/CommandTrayHost/configure.cpp +++ b/CommandTrayHost/configure.cpp @@ -72,21 +72,27 @@ bool initial_configure() * 但是参考各有不同: * cmd里面的子程序工作路径由working_directory指定 * 其他路径则是CommandTrayHost.exe所在目录指定 - * 4. 本文可以用系统自带的记事本编辑,然后保存选Unicode(大小端无所谓)或者UTF-8都可以 + * 4. 相对路径规则。首先绝对路径不会改变,规则只对相对路径有效,其次cmd只会相对path。 + * path: i) path为空且cmd为绝对路径,此时path会从cmd提取路径 + * ii) 除 i) 以外的相对路径都是相对于CommandTrayHost.exe所在路径 + * working_directory: + * i) 如果working_directory以>开头,那么它会相对于CommandTrayHost.exe所在目录 + * ii) 除 i) 以外的情况都是相对于经过处理过的path + * 5. 本文可以用系统自带的记事本编辑,然后保存选Unicode(大小端无所谓)或者UTF-8都可以 * 如果用VS Code或者Sublime Text编辑,可以用JSON with Comments语法着色 - * 5. 多个CommandTrayHost.exe只要放到不同目录,就可以同时运行与开机启动,互相不影响. 当然了默认配置是为了演示用, + * 6. 多个CommandTrayHost.exe只要放到不同目录,就可以同时运行与开机启动,互相不影响. 当然了默认配置是为了演示用, * 启用了全部热键,第二个启动时会提示热键冲突,禁用或者修改第二个的热键即可。 - * 6. 如果改成 "enable_cache": true ,则会将用户操作缓存到command_tray_host.cache + * 7. 如果改成 "enable_cache": true ,则会将用户操作缓存到command_tray_host.cache * 可以缓存用户的启用停用状态,窗口的位置大小,以及显示隐藏状态。作用下次启动 * CommandTrayHost.exe时,会忽略config.json里面的值。 * 缓存失效判定是与config.json之间的时间戳先后对比。缓存写入磁盘只会在全部操作(全部启用 * 全部禁用,全部显示隐藏),以及退出时发现缓存发生有效更改时才会写入磁盘。 - * 7. 全局热键格式: 可以使用alt win shift ctrl的任意个组合加上一个按键 + * 8. 全局热键格式: 可以使用alt win shift ctrl的任意个组合加上一个按键 * 加上的按键支持0-9的数字 A-Z的字母,其他特殊按钮,鼠标左右键,滚轮,甚至手柄按钮也是可以的.比如上方向键0x26 * 键盘码参考这里 https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx * 大小写无关,顺序无关,如果多个非修饰符的按钮,最后的那个按钮会起作用。 * 热键注册失败,一般是与系统中存在的冲突了,换一个再试 - * 8. crontab语法,秒 分 时 日期 月份 星期,比常规crontab多了个秒钟,具体语法使用搜索引擎 + * 9. crontab语法,秒 分 时 日期 月份 星期,比常规crontab多了个秒钟,具体语法使用搜索引擎 * 例子 0 0/10 * * * * 每10分钟运行一次 * 例子 0 1,11,21 * * * 每小时的1分 11分 21分运行一次 * 例子 0 2/10 12-14 * * * 12点到14点,每小时从2分钟开始每10分钟运行一次 @@ -98,7 +104,7 @@ bool initial_configure() "name": "cmd例子", // 系统托盘菜单名字 "path": "C:\\Windows\\System32", // cmd的exe所在目录,相对路径是可以的,参考目录是CommandTrayHost.exe所在目录 "cmd": "cmd.exe", // cmd命令,必须含有.exe - "working_directory": "", // 命令行的工作目录,为空时自动用path + "working_directory": "", // 命令行的工作目录. 如果是相对路径,>开头意味着相对于CommandTrayHost.exe,否则相对于path。 "addition_env_path": "", // dll搜索目录,暂时没用到 "use_builtin_console": false, // 是否用CREATE_NEW_CONSOLE,暂时没用到 "is_gui": false, // 是否是 GUI图形界面程序 @@ -249,7 +255,7 @@ bool initial_configure() "name": "cmd example", // Menu item name in systray "path": "C:\\Windows\\System32", // path which includes cmd exe, relative path is ok. "cmd": "cmd.exe", // must contain .exe - "working_directory": "", // working directory. empty is same as path + "working_directory": "", // working directory. relative to path usually. start with > symbol to use relative path from CommandTrayHost.exe "addition_env_path": "", //dll search path "use_builtin_console": false, //CREATE_NEW_CONSOLE "is_gui": false, diff --git a/CommandTrayHost/utils.cpp b/CommandTrayHost/utils.cpp index 4f3a217..bfdc7f1 100644 --- a/CommandTrayHost/utils.cpp +++ b/CommandTrayHost/utils.cpp @@ -133,7 +133,7 @@ std::wstring get_abs_working_directory(const std::wstring& path_wstring, const s return working_directory_wstring; } TCHAR abs_path[MAX_PATH * 128]; - if (working_directory_wstring.length() > 1 && working_directory_wstring[0] == L'>') + if (working_directory_wstring.length() >= 1 && working_directory_wstring[0] == L'>') { if (NULL == PathCombine(abs_path, szPathToExeDir, working_directory_wstring.c_str() + 1)) { From a53dc4d0e91d2032f153a1472ae79f4528976fce Mon Sep 17 00:00:00 2001 From: rexdf Date: Wed, 19 Dec 2018 20:33:04 +0800 Subject: [PATCH 42/46] :bookmark: 2.3.3 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d9be874..9809e2e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 2 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 3 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal From 9f1d88d882f9031a8c89593207f975e8a166dda7 Mon Sep 17 00:00:00 2001 From: rexdf Date: Fri, 28 Dec 2018 20:16:39 +0800 Subject: [PATCH 43/46] fix #39 --- CommandTrayHost/cron.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommandTrayHost/cron.cpp b/CommandTrayHost/cron.cpp index 23fbe0e..c33213f 100644 --- a/CommandTrayHost/cron.cpp +++ b/CommandTrayHost/cron.cpp @@ -73,7 +73,7 @@ void crontab_log(const nlohmann::json& jsp_crontab_config, //if (json_object_has_member(jsp, "crontab_config")) { //auto& crontab_config_ref = jsp["crontab_config"]; - int log_level = jsp_crontab_config["log_level"]; + int log_level = jsp_crontab_config.value("log_level", 0); if (log_level < log_level_limit) { return; } const size_t buffer_len = 256; char buffer[buffer_len]; From 58323df232eb150b87d065ddedc6fed55dcec2ce Mon Sep 17 00:00:00 2001 From: rexdf Date: Fri, 28 Dec 2018 20:40:18 +0800 Subject: [PATCH 44/46] :wrench: FileVersion is same as ProductVersion now --- version_set.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/version_set.py b/version_set.py index 446f8f6..a2fd78f 100644 --- a/version_set.py +++ b/version_set.py @@ -47,6 +47,10 @@ def main(): rc_string = r'VALUE "ProductVersion", "{}, {}, {}, {}\\0"'.format( MAJOR_VERSION, MINOR_VERSION, FIX_VERSION, build_version_number) # .encode('utf-8') + pattern2_rc = re.compile(r'^VALUE "FileVersion", "\d+, \d+, \d+, \d+[\\]0"', re.M) + rc_string2 = r'VALUE "FileVersion", "{}, {}, {}, {}\\0"'.format( + MAJOR_VERSION, MINOR_VERSION, FIX_VERSION, build_version_number) + pattern_stdafx_h = re.compile( r'^#define VERSION_NUMS L"\d+[.]\d+[.][0-9b-]+"', re.M) stdafx_h_string = r'#define VERSION_NUMS L"{}.{}.{}-b{}"'.format( @@ -61,6 +65,7 @@ def main(): for file_name, pattern_re, replace_string, encoding in ( (stdafx_h_file, pattern_stdafx_h, stdafx_h_string, 'utf-8'), (rc_file, pattern_rc, rc_string, 'utf-16le'), + (rc_file, pattern2_rc, rc_string2, 'utf-16le'), ): # CommandTrayHost.rc # stdafx.h print(f'opening {file_name}') From 49ed31b0b26673545c2bcc7f6556384ca7b1e945 Mon Sep 17 00:00:00 2001 From: rexdf Date: Fri, 28 Dec 2018 20:43:26 +0800 Subject: [PATCH 45/46] :wrench: FileVersion is same as ProductVersion now --- version_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version_set.py b/version_set.py index a2fd78f..8876155 100644 --- a/version_set.py +++ b/version_set.py @@ -60,7 +60,7 @@ def main(): rc_file = os.path.join(base_dir, "CommandTrayHost", "CommandTrayHost.rc") stdafx_h_file = os.path.join(base_dir, "CommandTrayHost", "stdafx.h") - print(stdafx_h_string, '\n', rc_string) + print(stdafx_h_string, '\n', rc_string, '\n', rc_string2) for file_name, pattern_re, replace_string, encoding in ( (stdafx_h_file, pattern_stdafx_h, stdafx_h_string, 'utf-8'), From 3b9f0e2a4e67559f6860e18f97b1d454260fb774 Mon Sep 17 00:00:00 2001 From: rexdf Date: Fri, 28 Dec 2018 20:41:13 +0800 Subject: [PATCH 46/46] :bookmark: 2.3.4 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 9809e2e..78c5395 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,7 +34,7 @@ before_build: - cmd: >- C:\Python36\Scripts\pip.exe install chardet pytz - C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 3 + C:\Python36\python.exe version_set.py %APPVEYOR_BUILD_NUMBER% 2 3 4 build: project: c:\projects\CommandTrayHost\CommandTrayHost.sln verbosity: minimal