此帖属于上一贴的更新,U盘解锁/锁屏——修改于坛友思路
/thread-1766402-1-1.html
上一贴作为python初学的技术交流贴,坛友提出了很多有意义、有建设性的建议,试着实现了一下,以下是相关内容。
必看:因为我打包的时候忘记删除配置文件,请下载压缩包后先删除config.ini,不然会直接被锁定,如果已经被锁定请重启电脑再删除文件目录下的config.ini。
适用场景:学校(教师正常使用,学生不能随便玩电脑)、公司(自己的电脑不方便给其他人用,设密码也不合适)、公用电脑(临时离开不方便关机)等等。
锁定方式:用 windll.user32.BlockInput(True) 屏蔽键盘和鼠标操作,界面不会有任何变化,此时只能调动ctrl+alt+del和锁屏热键,但由于循环锁定,所以依然不能进行其他操作。
授权方式:以下两种方式可同时开启,满足其一即可解锁电脑。
1.给指定U盘授权解锁电脑:判断U盘序列号是否在授权名单,不在名单的U盘不能操作电脑。
2.给U盘指定文件授权解锁电脑:判断U盘的指定路径中是否存在指定文件,存在就可以解锁。
使用方法:
初次打开软件:默认如果先插U盘再开软件,U盘会出现在已授权列表中。如果先打开软件再插入U盘,U盘会出现在未授权列表中,需要选中未授权列表中的每一项,逐个<添加>到授权U盘列表,同时也可以勾选<指定文件授权>,会弹出一个选择文件的窗口,选择想要指定的文件就好,所有的授权设置完成后一定要点击<保存>,最后<退出>。
第二次及以后启动软件:不会直接出现软件界面,会在任务栏界面出现一把锁,只能<右键>会出现菜单,点击<设置>就会打开软件界面,可以重新设置授权,界面实时刷新,可实时修改授权名单和设置,修改后记得点击<保存>,点击<退出>会解锁软件的所有进程。
开机自启:可以通过系统的启动文件夹或者注册表等任何方法实现自启,会触发目前已知唯二之一的bug,不会有窗口,任务栏也没有图标(绝对静默),但进程启动运行,功能正常,就是不能打开设置界面。如果需要调整授权,需要用任务管理器结束进程然后双击启动软件,然后任务栏就有图标了。
我解决不了(不想解决)的问题:
bug1:通过系统自启启动软件或者cmd启动软件任务栏不会出现图标,除此之外一切正常。
bug2:无论是点击界面内的退出还是状态栏右键退出,状态栏的图标都不会主动消失,需要鼠标从图标上经过一下才会消失,这个可能是我系统的bug。
打包后的文件很大(73M),cpu占用在锁定状态会多一些。
软件打包后图标右下角有个小盾牌,据网上说带有这个盾牌的程序设置开机自启有一定难度,我用vbs可以实现静默自启,但bug1依然存在。
代码不美观且难以理解。
最后会贴出源码和成品,希望坛友能指正优化一下我的程序。自学了基础部分,写这个程序遇到很多困难,csdn都查烂了。
软件还有不完善的地方,我有一些解决思路但懒,不一定啥时候修复,这是我写的第2个GUI工具,真的很佩服论坛里的大佬。
成品链接:https://www.123pan.com/s/TctA-nW5j.html
[Python] 纯文本查看 复制代码
from tkinter import END, Checkbutton, Listbox, Tk, Label, Button, filedialog, PhotoImage
from tkinter.messagebox import askokcancel
from ctypes import windll
from wmi import WMI
from os import _exit, path
from time import sleep
from threading import Thread
from pythoncom import CoInitialize
from pystray import MenuItem, Icon, Menu
from PIL import Image
# 状态栏图标
def icon():
def show_window():
global is_w
# 首次启动不显示窗口
if is_w == 0:
Thread(target=window).start()
is_w = 1
else:
root_windows.deiconify()
menu = (MenuItem('设置', show_window), MenuItem('退出', exit),
Menu.SEPARATOR)
image = Image.open("icon.png")
icon = Icon("icon", image, "授权已开启", menu)
icon.run()
# 设置主窗口
def window():
global is_update
global root_windows, listbox1, listbox2, listbox3, button1, button2, button3, button4, checkbutton
root_windows = Tk()
# 窗口大小,设置屏幕居中
screenwidth = root_windows.winfo_screenwidth()
screenheight = root_windows.winfo_screenheight()
root_windows.geometry(
f"419x260+{int((screenwidth-419)/2)}+{int((screenheight-236)/2)}")
root_windows.resizable(False, False)
root_windows.iconphoto(False, PhotoImage(file=f'{work_path}\\icon.png'))
root_windows.title("Lock_Screen_v1.1 by ifdess from 52pj.cn")
# 标签
lable1 = Label(root_windows, text="未授权U盘:")
lable1.place(x=20, y=10)
# 标签
lable2 = Label(root_windows, text="已授权U盘:")
lable2.place(x=255, y=10)
# 未授权列表框
listbox1 = Listbox(root_windows)
u_now = get_u()
for item in u_yes:
try:
u_now.remove(item)
except:
pass
for i in u_now:
listbox1.insert(END, i)
listbox1.place(x=20, y=35)
# 已授权列表框
listbox2 = Listbox(root_windows)
for i in u_yes:
listbox2.insert(END, i)
listbox2.place(x=255, y=35)
# 文件模式复选框
checkbutton = Checkbutton(root_windows,
text="指定文件授权", command=select_file)
checkbutton.place(x=16, y=226)
# 指定文件列表框
listbox3 = Listbox(root_windows, height=1, width=39)
if file_yes:
listbox3.insert(END, file_yes)
checkbutton.select()
else:
pass
listbox3.place(x=120, y=228)
# 添加按钮
button1 = Button(root_windows, text="添加 >>",
height=1, width=8, command=add)
button1.place(x=177, y=42)
# 删除按钮
button2 = Button(root_windows, text=" << 删除",
height=1, width=8, command=delete)
button2.place(x=177, y=89)
# 保存按钮
button3 = Button(root_windows, text="保存", height=1,
width=8, command=save_config)
button3.place(x=177, y=136)
# 退出按钮
button4 = Button(root_windows, text="退出", height=1, width=8, command=exit)
button4.place(x=177, y=183)
if is_update == 0:
Thread(target=update_u, daemon=True).start()
is_update = 1
# 设置叉是隐藏窗口
if path.exists(f"{work_path}/config.ini"):
root_windows.protocol("WM_DELETE_WINDOW", root_windows.withdraw)
else:
root_windows.protocol("WM_DELETE_WINDOW", exit)
root_windows.mainloop()
work_path = path.dirname(path.abspath(__file__))
# 保存配置文件
def save_config():
global u_yes, file_yes
with open(f"{work_path}\\config.ini", "w") as c:
c.write(str(u_yes)+"\n")
c.write(str(file_yes))
askokcancel(title="通知", message="配置保存成功。")
# 读取配置文件
def read_config():
global u_yes, file_yes
if path.exists(f"{work_path}/config.ini"):
with open(f"{work_path}\\config.ini", "r") as c:
u_yes = eval(c.readline())
file_yes = c.readline()
else:
u_yes = get_u()
file_yes = ""
# 获取U盘型号和序列号,保存为列表
def get_u(var=[]):
var = []
CoInitialize()
for item in WMI().Win32_DiskDrive():
if item.MediaType == "Removable Media":
var.append(item.Model+" "+item.SerialNumber)
return var
# 删除选中项
def delete():
global u_yes, listbox1, listbox2
try:
u_yes.remove(listbox2.get(listbox2.curselection()))
listbox2.delete(listbox2.curselection())
listbox1.delete(0, END)
except:
pass
# 添加选中项
def add():
global u_yes, listbox1, listbox2
u_yes.append(listbox1.get(listbox1.curselection()))
listbox2.insert(END, (listbox1.get(listbox1.curselection())))
listbox1.delete(listbox1.curselection())
# 核心判断程序,是否屏蔽
def run():
global is_w
while True:
if get_u() == []:
windll.user32.BlockInput(True)
else:
# 判断实时获取的U盘列表和刚开机时的U盘列表是否有交集,如果有就代表教师U盘仍旧保持插入
if list(set(get_u()).intersection(u_yes)) == []:
if is_file():
windll.user32.BlockInput(False)
else:
windll.user32.BlockInput(True)
else:
windll.user32.BlockInput(False)
sleep(0.001)
# 打开选择文件的窗口,并处理文件路径
def select_file():
global select_path, listbox3, file_yes, CheckBox
if len(file_yes) != 0:
file_yes = ""
listbox3.delete(0, END)
else:
selected_file_path = filedialog.askopenfilename()
file_yes = selected_file_path[2:]
if len(file_yes) == 0:
checkbutton.deselect()
else:
listbox3.delete(0, END)
listbox3.insert(END, selected_file_path[2:])
file_yes = selected_file_path[2:]
checkbutton.select()
# 遍历所有盘路径,判断授权文件是否存在
def is_file():
global file_yes
if len(file_yes) == 0:
return False
else:
for item in [chr(abc) for abc in range(97, 123)]:
if path.exists(f"{item}:{file_yes}"):
return True
def exit():
_exit(0)
# 更新显示列表
def update_u():
global listbox1
u_temp = []
while True:
u_now = get_u()
for item in u_yes:
try:
u_now.remove(item)
except:
pass
if u_now != u_temp and u_now != None:
listbox1.delete(0, END)
u_temp = u_now
for item in u_now:
listbox1.insert(END, item)
else:
pass
sleep(0.001)
# 程序开始
read_config()
if path.exists(f"{work_path}/config.ini"):
is_w = 0
is_update = 0
Thread(target=icon).start()
Thread(target=run).start()
else:
is_update = 0
window()