From d460d4db587234dc7c4de7012c1abc1408f2b4ae Mon Sep 17 00:00:00 2001 From: ZiHaoSaMa66 <134737096+ZiHaoSaMa66@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:57:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0USB=E7=AE=A1=E6=8E=A7?= =?UTF-8?q?=E7=9A=84=E5=9F=BA=E7=A1=80=E7=AE=A1=E7=90=86=20=E5=92=8C=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20#44?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/REmainv3.py | 159 ++++++++++++++++++++---------------------------- src/remain.py | 124 ++++++++++++++++++++++++++----------- 2 files changed, 156 insertions(+), 127 deletions(-) diff --git a/src/REmainv3.py b/src/REmainv3.py index 5c75095..b83d690 100644 --- a/src/REmainv3.py +++ b/src/REmainv3.py @@ -15,6 +15,8 @@ # 0.18.0 import random +import ctypes +from ctypes import wintypes from pynput import keyboard @@ -26,7 +28,7 @@ class Ui: def __init__(self) -> None: - self.ver = "OsEasy-ToolBox v1.7 Beta4" + self.ver = "OsEasy-ToolBox v1.7 RC2.1" self.runwindows_lis = keyboard.Listener(on_press=self.run_windowskjj_onpress) @@ -221,16 +223,13 @@ def main(self, bruh: ft.Page): self.page.theme = ft.Theme(font_family="ht") self.page.update() - self.page.window_height = 615 + self.page.window_height = 635 self.page.window_width = 450 self.page.window_max_height = 2000 self.page.window_max_width = 455 - self.page.window_min_height = 500 - self.page.window_min_width = 449 - - self.page.window_min_height = 500 + self.page.window_min_height = 620 self.page.window_min_width = 449 self.page.update() @@ -377,7 +376,9 @@ def main(self, bruh: ft.Page): on_click=self.reflashStudentPath, ), ft.FilledTonalButton( - text="注册粘滞键替换", icon=ft.icons.COPY_SHARP, on_click=selfunc_g1 + text="注册粘滞键替换", + icon=ft.icons.FILE_COPY_ROUNDED, + on_click=selfunc_g1, ), ft.Switch( label="外部cmd守护进程", @@ -410,27 +411,27 @@ def main(self, bruh: ft.Page): ft.FilledTonalButton( text="长按恢复所有备份文件", icon=ft.icons.RESTORE, - on_long_press=lambda e: restoneKeyDll, + on_long_press=lambda _: restoneKeyDll(), ), ft.FilledTonalButton( text="长按以恢复黑屏安静程序", icon=ft.icons.ACCOUNT_BOX, - on_long_press=restoneBlackSlt, + on_long_press=lambda _: restoneBlackSlt(), ), ft.FilledTonalButton( text="长按以仅恢复控屏锁定程序", icon=ft.icons.SCREEN_SHARE_SHARP, - on_long_press=restoneMutClient, + on_long_press=lambda _: restoneMutClient(), ), ft.FilledTonalButton( text="停止网络管控服务(不可逆)", icon=ft.icons.WIFI_PASSWORD_SHARP, - on_click=self.forunlocknettips, + on_click=lambda _: self.forunlocknettips(), ), ft.FilledTonalButton( text="[无法正常工作] 关闭USB管控服务", icon=ft.icons.USB_SHARP, - on_click=self.usb_unlock_tips, + on_click=lambda _: self.usb_unlock_tips(), ), self.FastGetSC, ] @@ -440,7 +441,7 @@ def main(self, bruh: ft.Page): # 自动生成命令 self.auto_gennerate_cmd = ft.FilledTonalButton( text="由教师机IP生成远程命令", - icon=ft.icons.CODE, + icon=ft.icons.DRAW, on_click=lambda _: generate_yc_cmd_and_save(self.teachIp_input.value), ) @@ -450,7 +451,7 @@ def main(self, bruh: ft.Page): on_click=lambda _: handin_save_yc_cmd( self.conl_save_ycCmd_input.value, True ), - icon=ft.icons.UPDATE, + icon=ft.icons.DRAW, ) self.conl_ycCmd_update = ft.FilledTonalButton( @@ -458,7 +459,7 @@ def main(self, bruh: ft.Page): on_click=lambda _: handin_save_yc_cmd( self.conl_save_ycCmd_input.value, False ), - icon=ft.icons.UPDATE, + icon=ft.icons.MODE_EDIT_SHARP, ) self.conl_from_log_get_cmd = ft.FilledTonalButton( @@ -840,110 +841,82 @@ def SWC_MainPages_6(self): ] ) - if self.loaded_bg == True: - - bgb = ft.Stack(controls=[self.col_imgbg, self.AboutTab_Stuff]) - - nedadd = ft.Row( - [self.MyRail, ft.VerticalDivider(width=0), bgb], - height=self.page.window_height, - width=self.page.window_width, - ) - - self.page.clean() - self.page.update() - self.page.add(nedadd) - self.page.update() - - else: - - nedadd = ft.Row( - [self.MyRail, ft.VerticalDivider(width=0), self.AboutTab_Stuff], - height=self.page.window_height, - width=self.page.window_width, - ) - self.page.clean() - self.page.update() - self.page.add(nedadd) - self.page.update() - - def dll_test_case_fill_helper( - self, filename: str, funcname: str, returntype: str - ) -> None: - """自动填充测试用例的辅助函数""" - self.dllname_input.value = filename - self.dll_func_input.value = funcname - self.dll_return_input.value = returntype - self.page.update() + self.apply_bg_to_ui(needLoad_Stuff_list=self.AboutTab_Stuff) def SWC_MainPages_4(self): """切换至页面4 dll 调试工具""" - self.dllname_input = ft.TextField(label="学生端目录下的完整路径+文件名") - # Dll 名称 如: xxx.dll - self.dll_func_input = ft.TextField(label="调用的导出函数名") - # Dll 内的导出函数 如: GetUserNameA - self.dll_return_input = ft.TextField(label="返回值的类型(int, bool, char)") - # 返回值的类型 bool , int , char , long , double - - self.dll_confirm_btn = ft.FilledTonalButton( - text="执行函数", - on_click=lambda _: dev_test_use_dll( - self.dllname_input.value, - self.dll_func_input.value, - self.dll_return_input.value, - ), - icon=ft.icons.CODE, - ) - self.dll_test_case_1 = ft.FilledTonalButton( - text="自动填入:Usb_StopWorking", - on_click=lambda _: self.dll_test_case_fill_helper( + self.dll_usb_1 = ft.FilledTonalButton( + text="执行:关闭USB管控", + on_click=lambda _: run_easy_dll( "\\x64\\easyusbctrl.dll", "EasyUsb_StopWorking", - "int", + ctypes.c_int, + [], + None, ), + icon=ft.icons.USB, ) - self.dll_test_case_2 = ft.FilledTonalButton( - text="自动填入:Usb_StartWorking", - on_click=lambda _: self.dll_test_case_fill_helper( + self.dll_usb_2 = ft.FilledTonalButton( + text="执行:启动USB管控", + on_click=lambda _: run_easy_dll( "\\x64\\easyusbctrl.dll", "EasyUsb_StartWorking", - "int", + ctypes.c_int, + [], + None, + ), + icon=ft.icons.USB_OFF, + ) + + self.dll_usb_3 = ft.FilledTonalButton( + text="执行:查询USB管控状态", + on_click=lambda _: run_easy_dll( + "\\x64\\easyusbctrl.dll", + "EasyUsb_IsWorking", + ctypes.c_int, + [ctypes.POINTER(wintypes.DWORD)], + wintypes.DWORD(0), ), + icon=ft.icons.CODE, ) - self.dll_test_case_3 = ft.FilledTonalButton( - text="自动填入:开启网络管控", - on_click=lambda _: self.dll_test_case_fill_helper( + self.dll_net_1 = ft.FilledTonalButton( + text="执行:开启网络管控", + on_click=lambda _: run_easy_dll( "\\x64\\OeNetlimit.dll", "DisableInternet", - "int", + ctypes.c_int, + [], + None, ), - icon=ft.icons.PENDING_OUTLINED, + icon=ft.icons.SIGNAL_WIFI_CONNECTED_NO_INTERNET_4, ) - self.dll_test_case_4 = ft.FilledTonalButton( - text="自动填入:关闭网络管控", - on_click=lambda _: self.dll_test_case_fill_helper( + self.dll_net_2 = ft.FilledTonalButton( + text="执行:关闭网络管控", + on_click=lambda _: run_easy_dll( "\\x64\\OeNetlimit.dll", "EnableNet", - "int", + ctypes.c_int, + [], + None, ), - icon=ft.icons.PENDING_OUTLINED, + icon=ft.icons.SIGNAL_WIFI_4_BAR, ) + # self.dll_test_case_5 = ft.FilledTonalButton( + self.dllTab_Stuff = ft.Column( controls=[ - # ft.Text("在操作前请确保你知道参数应该填什么", size=19, color="red"), - self.dllname_input, - self.dll_func_input, - self.dll_return_input, - self.dll_test_case_1, - self.dll_test_case_2, - self.dll_test_case_3, - self.dll_test_case_4, - self.dll_confirm_btn, + self.yiyanshowtext, + ft.Divider(height=1), + self.dll_usb_1, + self.dll_usb_2, + self.dll_usb_3, + self.dll_net_1, + self.dll_net_2, ] ) diff --git a/src/remain.py b/src/remain.py index 92ab94a..65a39f9 100644 --- a/src/remain.py +++ b/src/remain.py @@ -6,6 +6,7 @@ import pygetwindow as gw import webbrowser import ctypes +from ctypes import wintypes import sys import psutil import pyautogui @@ -70,37 +71,42 @@ def get_error_message(self, error_code): return msg_buffer.value -def dev_test_use_dll(dll_name, func_name, return_type): +def run_easy_dll( + dll_name, func_name, return_type, argtypes, out_buffer, after_run_func=None +): + """ + ### 参数 + - `dll_name`: 要调用的dll文件名 + - `func_name`: 要调用的函数名 + - `return_type`: 要调用的函数的返回值类型 + - `argtypes`: 要调用的函数的参数类型 + - `out_buffer`: 要调用的函数的输出参数 + - `after_run_func`: 运行完毕后的回调函数 + """ - print("debug >",dll_name,func_name,return_type) - print('type >',type(dll_name),type(func_name),type(return_type)) + print("dllUse debug >", dll_name, func_name, return_type, argtypes, out_buffer) # dll_path = "" + dll_name dll_path = ToolBoxCfg.oseasypath + dll_name easy_dll = EasyDll(dll_path) - useType = { - "bool": ctypes.c_bool, - "int": ctypes.c_int, - "long": ctypes.c_long, - "double": ctypes.c_double, - "char": ctypes.c_char, - } - - runner = easy_dll.setup_function( - func_name, restype=useType[return_type], argtypes=[] - ) + runner = easy_dll.setup_function(func_name, restype=return_type, argtypes=argtypes) try: - result = runner() + if out_buffer == None: + result = runner() + else: + result = runner(out_buffer) except Exception as e: Ui_CallShowSnakeMessage(f"调用失败 抛出异常:\n{e}") print("[DEBUG] dll result:", result) - ui_show_msg = f"Result:\nName: {func_name}\n返回值: {result}" + ui_show_msg = f"运行结果: \n函数: {func_name}\n返回值: {result}" + if out_buffer != None: + ui_show_msg += f"\n输出参数: {out_buffer.value}" if result != 0: error_msg = easy_dll.get_error_message(result) @@ -109,6 +115,9 @@ def dev_test_use_dll(dll_name, func_name, return_type): Ui_CallShowSnakeMessage(ui_show_msg) + if after_run_func != None: + after_run_func() + class ToolBoxConfig: @@ -196,6 +205,28 @@ def set_style_path(self, style_name: str, style_path: str) -> None: jData[style_name] = style_path self.write_config(jData) +def get_god_potato_path(): + # PyInstaller 提取的临时路径 + if hasattr(sys, "_MEIPASS"): + return os.path.join(sys._MEIPASS, "resources", "gp_net35.exe") + # 开发环境路径 + return os.path.join("resources", "gp_net35.exe") + +def run_cmd_with_god_potato(arguments:str): + """ + 使用神の土豆来运行命令 + 参数: + - arguments: 要运行的命令 + 如:run_god_potato_cmd("net start MMPC") + """ + ntsd_path = get_god_potato_path() + if not os.path.exists(ntsd_path): + raise FileNotFoundError(f"ntsd.exe not found at {ntsd_path}") + + cmd = f'"{ntsd_path}" -cmd "cmd /c {arguments}"' + + runcmd(cmd,False) + ToolBoxCfg = ToolBoxConfig() @@ -345,7 +376,7 @@ def HighVer_CloseMMPCProtect_Helper(): pass -def HighVer_AddMMPC_Control_CommandLine(IsStop=True): +def HighVer_AddMMPC_Control_CommandLine(IsStop = True): """检查学生端版本 返回根服务控制指令\n 用于直接插入到脚本中 """ @@ -354,7 +385,7 @@ def HighVer_AddMMPC_Control_CommandLine(IsStop=True): _ = tryGuessStudentClientVer() if ToolBoxCfg.running_student_client_ver >= 109: - if IsStop: + if IsStop == True: return "sc stop MMPC\n" else: return "sc start MMPC\n" @@ -416,6 +447,7 @@ def get_yuancheng_cmd() -> str | None: except FileNotFoundError: return None + def parse_screenrender_log(): """ 读取 `%appdata%/Mmc/ScreenRender.log` 文件,\n @@ -426,31 +458,31 @@ def parse_screenrender_log(): `list`: 包含处理后的命令部分的列表。 """ # 获取 %appdata% 路径 - appdata_path = os.getenv('APPDATA') + appdata_path = os.getenv("APPDATA") if not appdata_path: # raise EnvironmentError("无法获取 %APPDATA% 路径") Ui_CallShowSnakeMessage("无法获取 %APPDATA% 路径") return False, [] - log_path = os.path.join(appdata_path, 'Mmc', 'ScreenRender.log') + log_path = os.path.join(appdata_path, "Mmc", "ScreenRender.log") if not os.path.exists(log_path): # raise FileNotFoundError(f"日志文件不存在: {log_path}") Ui_CallShowSnakeMessage(f"日志文件不存在: {log_path}") return False, [] # 匹配特定格式的正则表达式 - pattern = re.compile(r'\d{2}-\d{2} \d{2}:\d{2}:\d{2} (\{.*\})') + pattern = re.compile(r"\d{2}-\d{2} \d{2}:\d{2}:\d{2} (\{.*\})") result = [] try: - with open(log_path, 'r', encoding='gbk') as log_file: + with open(log_path, "r", encoding="gbk") as log_file: for line in log_file: match = pattern.search(line) if match: command = match.group(1) # 替换 " 为 # - processed_command = command.replace('"', '#') + processed_command = command.replace('"', "#") result.append(processed_command) except Exception as e: # raise RuntimeError(f"读取日志文件时发生错误: {e}") @@ -462,13 +494,15 @@ def parse_screenrender_log(): return True, result + # "C:\Program Files (x86)\Os-Easy\os-easy multicast teaching system\ScreenRender.exe" {#decoderName#:#h264#,#fullscreen#:0,#local#:#172.18.36.132#,#port#:7778,#remote#:#229.1.36.200#,#teacher_ip#:0,#verityPort#:7788} -def save_scr_log_cmd_to_file(log_list = None) -> None: + +def save_scr_log_cmd_to_file(log_list=None) -> None: """传入`parse_screenrender_log`函数返回的命令列表\n 或直接调用\n 保存广播命令日志中的命令到文件""" - + if log_list == []: return elif log_list == None: @@ -481,15 +515,14 @@ def save_scr_log_cmd_to_file(log_list = None) -> None: def from_scr_log_cmd_get_yccmd() -> None: """从屏幕广播日志中提取广播命令\n并保存到文件""" - + status, log_list = parse_screenrender_log() if not status: return - + save_scr_log_cmd_to_file(log_list) - - handin_save_yc_cmd(log_list[0]) - + + handin_save_yc_cmd(log_list[0], replace_ip=False) def get_ipv4_address() -> str | None: @@ -738,7 +771,7 @@ def summon_unlocknet() -> None: fm = open(mp, "w") cmdtext = f"""@ECHO OFF\n title OsEasyToolBoxUnlockNetHeler\n - {HighVer_AddMMPC_Control_CommandLine(isStop=True)} + {HighVer_AddMMPC_Control_CommandLine(True)} :a\n taskkill /f /t /im {ToolBoxCfg.studentExeName}\n taskkill /f /t /im DeviceControl_x64.exe\n @@ -786,7 +819,7 @@ def summon_killer() -> None: cmdtext = f"""@ECHO OFF\n title OsEasyToolBoxKiller\n - {HighVer_AddMMPC_Control_CommandLine(isStop=True)} + {HighVer_AddMMPC_Control_CommandLine(True)} taskkill /f /t /im MultiClient.exe\n taskkill /f /t /im MultiClient.exe\n @@ -852,14 +885,37 @@ def restoneKeyDll() -> None: "MultiClient.exe", "LoadDriver.exe", "BlackSlient.exe", - "\\x86\\LISSNetInfoSniffer.exe", + # "\\x86\\LISSNetInfoSniffer.exe", ] + + faild_file_name = [] + for filename in namelist: oepath = ToolBoxCfg.oseasypath + filename needbkpath = bkppath + "\\" + filename runcmd(f'copy "{needbkpath}" "{oepath}"') - pass + + time.sleep(3) + + for filename in namelist: + + oepath = ToolBoxCfg.oseasypath + filename + + cSta = checkPointFileIsExcs(oepath) + + print(f"filename {filename} 复制检测状态 > {cSta}") + + if not cSta: + faild_file_name.append(filename) + + if len(faild_file_name) > 0: + msg_mix = " , ".join(faild_file_name) + Ui_CallShowSnakeMessage(f"在恢复文件时检测到可能复制失败的文件有: \n{msg_mix}") + return + + Ui_CallShowSnakeMessage("恢复文件完成") + def runbat(batname: str) -> None: