(一)Pyinstaller 打包
前两天用Python做了一个小工具,调用一个DLL文件,获取公司平板设备标识码,然后将标识码复制到粘贴板
用Python做挺好做的,使用 ctypes
调用DLL,使用 pyperclip
包操作粘贴板
#!/bin/env python
# -*- coding: utf-8 -*-
import tkinter.ttk as ttk
import tkinter as tk
import pyperclip
import ctypes
import sys
def get_x3id():
'''获取X3唯一标识'''
lib= ctypes.CDLL('PcInfo.dll')
r = lib.GetHylinkDeviceId()
value = ctypes.c_char_p(r).value
x3id = bytes2str(value)
print("x3id: ", x3id, type(x3id))
return x3id
def bytes2str(message):
'''
convert string to bytes, py2, py3
'''
if sys.version_info < (3, 4):
print("py2")
return message
else:
print("py3")
return message.decode("utf-8")
class Application(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.textBox()
self.button()
self.grid()
self.start()
def start(self):
'''校验是否在X3上使用'''
lib= ctypes.CDLL('PcInfo.dll')
v = lib.IsHylinkProduct()
if v == -1:
self.outputText.insert(tk.INSERT, '')
self.outputText.see("end")
msg = "\n 请在X3上使用本工具\n"
self.b1.config(state=tk.DISABLED)
else:
self.x3id = get_x3id()
msg = "\n 标识码: " + self.x3id + '\n'
self.outputText.insert(tk.INSERT, msg)
self.outputText.see("end")
def copy_and_close(self):
pyperclip.copy(self.x3id)
spam = pyperclip.paste()
app.quit()
def button(self):
self.button_msg = tk.StringVar()
self.button_msg.set('复制到粘贴板并关闭')
self.b1 = ttk.Button(self, textvariable=self.button_msg, command=self.copy_and_close)
self.b1.grid(row=1, column=0, columnspan=2, ipadx=60, ipady = 12, padx=(10, 0), pady=(0, 20))
# ipadx=70, ipady = 12
def textBox(self):
self.outputText = tk.Text(self, width=40, height=5)
self.outputText.grid(row=0, column=0, columnspan=2, padx=(30, 30), pady=(30, 20))
app = Application()
app.mainloop()
因为python2与python3在编码上边有些差异,所以使用 bytes2str
函数做了一下转换
Python程序要给别人使用,所以需要打个包,不然其它没有python环境的电脑是无法使用的
就这样,我用 pyinstaller
对程序进行打包,生成了一个exe文件
这个程序7M大小,测试过程中,启动速度有点慢,7.36秒才能加载完成,使用起来等待还挺明显的
最开始我以为是GUI拖慢的速度,使用界面,然后点击“复制到粘贴板并关闭”,其实没有界面也是没有关系的
于是我把GUI的代码去掉,做了个无GUI版本的,证实我的猜测是错误的,打包大小还是那么大,运行的速度也还是那么慢,影响性能的瓶颈是因为使用了pyinstaller
打包
(二)Nuitka 打包
在网上无意间发现了这个工具。我在虚拟机中安装了32位的python,并且安装了vs2008,它把python代码转换成python调用C API的形式,然后使用C编译器进行编译,官网说,它比Cython快一点点,最终会生成可执行程序
nuitka --standalone --windows-disable-console .\get_x3id.py
- standalone 参数是把需要的库都放在可执行程序的当前文件夹,便于分发
- windows-disable-console 默认启动会从cmd启动,带有一个黑窗口,使用这个参数就可以去掉了
这次生成的exe文件打开速度快很多,基本上1s就可以打开,相比于pyinstaller
,它的速度快了很多,但是它生成的不是单一的exe文件,分发的时候需要打包整个文件夹
(三)番外,Rust重构
在我发现 Nuitka 之前,我为了能让这个小工具速度快些费了一些心思,可是pyinstaller着实性能有点差...
于是我想着用一门性能好点的语言重写一下,反正就两个函数,加载DLL、复制内容到粘贴板
前阵学习Rust,一直在看书,还没写过什么东西,正好拿来练手
extern crate clipboard;
use clipboard::ClipboardProvider;
use clipboard::ClipboardContext;
extern crate libloading;
use libloading::{Library, Symbol};
use std::ffi::CStr;
use std::str;
type GetHylinkDeviceId = unsafe fn() -> *const i8;
fn copy_to_clipboard(x3id: String) {
let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap();
println!("{:?}", ctx.get_contents());
ctx.set_contents(x3id);
}
fn get_x3id() -> String {
let library_path = "PcInfo.dll";
println!("Loading add() from {:?}", library_path);
let lib = Library::new(library_path).unwrap();
let x3id = unsafe {
let func: Symbol<GetHylinkDeviceId> = lib.get(b"GetHylinkDeviceId").unwrap();
let c_buf: *const i8 = func();
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
let str_slice: &str = c_str.to_str().unwrap();
let str_buf: String = str_slice.to_owned();
str_buf
};
x3id
}
fn main() {
// 从DLL中获取X3标识码
let x3id: String = get_x3id();
println!("{:?}", x3id);
// 将标识码复制到粘贴板
copy_to_clipboard(x3id)
}
Rust 写起来比C/C++舒服很多,不过感觉还是没有python来的顺畅,可能是因为不熟练的缘故
使用cargo创建的工程,生成单独的exe文件,大小也很良心,除了外部自己的dll,只有1.58M
最后留个坑,不知道cargo如何把自己的dll打包到exe里面,这样分发使用就更方便了
<这里以后来填坑>