import
os
import
sys
import
subprocess
import
argparse
from
tkinter
import
Tk, filedialog, messagebox
import
tempfile
import
shutil
def
convert_to_exe(input_file, output_file
=
None
, icon
=
None
, onefile
=
True
, windowed
=
True
):
if
not
os.path.exists(input_file):
print
(f
"错误: 文件 '{input_file}' 不存在"
)
return
False
file_ext
=
os.path.splitext(input_file)[
1
].lower()
if
file_ext
not
in
[
'.bat'
,
'.vbs'
]:
print
(f
"错误: 不支持的文件类型 '{file_ext}',仅支持 .bat 和 .vbs 文件"
)
return
False
if
output_file
is
None
:
output_file
=
os.path.splitext(input_file)[
0
]
+
'.exe'
temp_dir
=
tempfile.mkdtemp()
try
:
wrapper_file
=
os.path.join(temp_dir,
'wrapper.py'
)
with
open
(wrapper_file,
'w'
, encoding
=
'utf-8'
) as f:
f.write(f
)
shutil.copy2(input_file, os.path.join(temp_dir, os.path.basename(input_file)))
cmd
=
[
'pyinstaller'
,
'--clean'
]
if
onefile:
cmd.append(
'--onefile'
)
if
windowed:
cmd.append(
'--windowed'
)
if
icon
and
os.path.exists(icon):
cmd.extend([
'--icon'
, icon])
cmd.extend([
'--name'
, os.path.splitext(os.path.basename(output_file))[
0
]])
cmd.extend([
'--distpath'
, os.path.dirname(output_file)])
cmd.extend([
'--workpath'
, os.path.join(temp_dir,
'build'
)])
cmd.append(wrapper_file)
print
(
"正在转换文件..."
)
result
=
subprocess.run(cmd, capture_output
=
True
, text
=
True
)
if
result.returncode !
=
0
:
print
(f
"错误: PyInstaller 执行失败"
)
print
(result.stderr)
return
False
print
(f
"转换成功! 输出文件: {output_file}"
)
return
True
finally
:
shutil.rmtree(temp_dir, ignore_errors
=
True
)
def
main():
parser
=
argparse.ArgumentParser(description
=
'将 .bat 或 .vbs 文件转换为 .exe 文件'
)
parser.add_argument(
'input_file'
, nargs
=
'?'
,
help
=
'输入的 .bat 或 .vbs 文件路径'
)
parser.add_argument(
'-o'
,
'--output'
,
help
=
'输出的 .exe 文件路径'
)
parser.add_argument(
'-i'
,
'--icon'
,
help
=
'可执行文件的图标路径 (.ico)'
)
parser.add_argument(
'--multi-file'
, action
=
'store_true'
,
help
=
'打包为多个文件而不是单个文件'
)
parser.add_argument(
'--console'
, action
=
'store_true'
,
help
=
'显示控制台窗口'
)
parser.add_argument(
'--gui'
, action
=
'store_true'
,
help
=
'使用图形界面'
)
args
=
parser.parse_args()
if
args.gui
or
not
args.input_file:
root
=
Tk()
root.withdraw()
input_file
=
filedialog.askopenfilename(
title
=
"选择 .bat 或 .vbs 文件"
,
filetypes
=
[(
"批处理文件"
,
"*.bat"
), (
"VBS文件"
,
"*.vbs"
), (
"所有文件"
,
"*.*"
)]
)
if
not
input_file:
messagebox.showinfo(
"信息"
,
"未选择文件,程序退出"
)
return
output_file
=
filedialog.asksaveasfilename(
title
=
"保存为 .exe 文件"
,
defaultextension
=
".exe"
,
filetypes
=
[(
"可执行文件"
,
"*.exe"
), (
"所有文件"
,
"*.*"
)]
)
if
not
output_file:
messagebox.showinfo(
"信息"
,
"未指定输出文件,程序退出"
)
return
icon_file
=
filedialog.askopenfilename(
title
=
"选择图标文件 (可选)"
,
filetypes
=
[(
"图标文件"
,
"*.ico"
), (
"所有文件"
,
"*.*"
)]
)
onefile
=
not
messagebox.askyesno(
"选项"
,
"是否打包为多个文件?"
)
windowed
=
not
messagebox.askyesno(
"选项"
,
"是否显示控制台窗口?"
)
if
icon_file:
icon
=
icon_file
else
:
icon
=
None
success
=
convert_to_exe(
input_file
=
input_file,
output_file
=
output_file,
icon
=
icon,
onefile
=
onefile,
windowed
=
windowed
)
if
success:
messagebox.showinfo(
"成功"
, f
"文件已成功转换为: {output_file}"
)
else
:
messagebox.showerror(
"错误"
,
"文件转换失败"
)
else
:
convert_to_exe(
input_file
=
args.input_file,
output_file
=
args.output,
icon
=
args.icon,
onefile
=
not
args.multi_file,
windowed
=
not
args.console
)
if
__name__
=
=
"__main__"
:
main()