使用pyinstaller、nuitka等打包工具打包python程序之后,会遇到各种奇奇怪怪问题,例如win32gui 就加载不了。
在pycharm下新建一个test.py文件,内容:
import win32gui
print(win32gui)
鼠标放在win32gui这个字符串上,安装ctrl键,点击鼠标,跳转到如下路径:
*****\AppData\Local\JetBrains\PyCharmCE2020.2\python_stubs\20717174
内容如下:
# encoding: utf-8
# module win32gui
# from C:\Users\lch\AppData\Local\Programs\Python\Python38\lib\site-packages\win32\win32gui.pyd
# by generator 1.147
# no doc
# imports
from pywintypes import error
# Variables with simple values
CLR_NONE = -1
dllhandle = 1931608064
ILC_COLOR = 0
ILC_COLOR16 = 16
ILC_COLOR24 = 24
ILC_COLOR32 = 32
ILC_COLOR4 = 4
ILC_COLOR8 = 8
ILC_COLORDDB = 254
ILC_MASK = 1
ILD_BLEND = 4
ILD_BLEND25 = 2
ILD_BLEND50 = 4
ILD_FOCUS = 2
ILD_MASK = 16
ILD_NORMAL = 0
ILD_SELECTED = 4
ILD_TRANSPARENT = 1
IMAGE_BITMAP = 0
IMAGE_CURSOR = 2
IMAGE_ICON = 1
LR_CREATEDIBSECTION = 8192
LR_DEFAULTCOLOR = 0
LR_DEFAULTSIZE = 64
LR_LOADFROMFILE = 16
LR_LOADMAP3DCOLORS = 4096
LR_LOADTRANSPARENT = 32
LR_MONOCHROME = 1
LR_SHARED = 32768
LR_VGACOLOR = 128
NIF_ICON = 2
NIF_INFO = 16
NIF_MESSAGE = 1
NIF_STATE = 8
NIF_TIP = 4
NIIF_ERROR = 3
NIIF_ICON_MASK = 15
NIIF_INFO = 1
NIIF_NONE = 0
NIIF_NOSOUND = 16
NIIF_WARNING = 2
NIM_ADD = 0
NIM_DELETE = 2
NIM_MODIFY = 1
NIM_SETVERSION = 4
TPM_BOTTOMALIGN = 32
TPM_CENTERALIGN = 4
TPM_LEFTALIGN = 0
TPM_LEFTBUTTON = 0
TPM_NONOTIFY = 128
TPM_RETURNCMD = 256
TPM_RIGHTALIGN = 8
TPM_RIGHTBUTTON = 2
TPM_TOPALIGN = 0
TPM_VCENTERALIGN = 16
UNICODE = True
# functions
def AbortPath(*args, **kwargs): # real signature unknown
pass
def AlphaBlend(*args, **kwargs): # real signature unknown
pass
def AngleArc(*args, **kwargs): # real signature unknown
pass
def AnimateWindow(*args, **kwargs): # real signature unknown
pass
def AppendMenu(*args, **kwargs): # real signature unknown
pass
def Arc(*args, **kwargs): # real signature unknown
pass
def ArcTo(*args, **kwargs): # real signature unknown
pass
def BeginPaint(*args, **kwargs): # real signature unknown
pass
def BeginPath(*args, **kwargs): # real signature unknown
pass
def BitBlt(*args, **kwargs): # real signature unknown
pass
def BringWindowToTop(*args, **kwargs): # real signature unknown
pass
def CallWindowProc(*args, **kwargs): # real signature unknown
pass
def CheckMenuItem(*args, **kwargs): # real signature unknown
pass
def CheckMenuRadioItem(*args, **kwargs): # real signature unknown
pass
def ChildWindowFromPoint(*args, **kwargs): # real signature unknown
pass
def ChildWindowFromPointEx(*args, **kwargs): # real signature unknown
pass
def Chord(*args, **kwargs): # real signature unknown
pass
def ClientToScreen(*args, **kwargs): # real signature unknown
pass
def CloseFigure(*args, **kwargs): # real signature unknown
pass
切换到
***\AppData\Local\Programs\Python\Python38\Lib\site-packages
目录下,“ctrl+F”输入“win32gui”
在win32目录下找到win32gui.pyd文件
执行’test.py’打印结果与前面第二步指向的路径一致,win32/win32gui.pyd是我们要找到包。
新建main.py文件
# -*- coding: utf-8 -*-
import sys, traceback
import sys, traceback
from PyQt5.QtWidgets import QWidget,QApplication
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QWidget,QApplication
class WDTPubDispatch(QWidget,Ui_Form):
def __init__(self, parent=None):
super(WDTPubDispatch, self).__init__(parent=parent)
self.setupUi(self)
self.initUI()
def __del__(self):
print(self.__class__,'del')
def initUI(self):
# 菜单模块
self.btnRun.clicked.connect(self.run)
def run(self):
# 加载数据
txtFunc = self.txtFunc.toPlainText()
try:
exec(txtFunc)
except:
traceback.print_exc()
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(567, 476)
self.verticalLayout = QtWidgets.QVBoxLayout(Form)
self.verticalLayout.setObjectName("verticalLayout")
self.label_4 = QtWidgets.QLabel(Form)
self.label_4.setObjectName("label_4")
self.verticalLayout.addWidget(self.label_4)
self.btnRun = QtWidgets.QPushButton(Form)
self.btnRun.setObjectName("btnRun")
self.verticalLayout.addWidget(self.btnRun)
self.label_6 = QtWidgets.QLabel(Form)
self.label_6.setObjectName("label_6")
self.verticalLayout.addWidget(self.label_6)
self.txtFunc = QtWidgets.QTextEdit(Form)
self.txtFunc.setObjectName("txtFunc")
self.verticalLayout.addWidget(self.txtFunc)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label_4.setText(_translate("Form", "通用数据处理"))
self.label_4.setProperty("qsslevel", _translate("Form", "subtitle"))
self.btnRun.setText(_translate("Form", "执行"))
self.label_6.setText(_translate("Form", "输入函数:"))
self.txtFunc.setHtml(_translate("Form", "\n"
"\n"
"
"))
if __name__ == '__main__':
app = QApplication(sys.argv)
windows = WDTPubDispatch()
windows.show()
app.exec_()
采用nuitka打包,带命令行调试版本:
python -m nuitka --mingw64 --standalone --show-progress --show-memory --plugin-enable=qt-plugins --plugin-enable=pylint-warnings --nofollow-import-to=numpy,jinja2,matplotlib,scipy,sqlalchemy,pandas,pygal,pyzbar,pubunit,qtunit,dataunit,Crypto --output-dir=D:\打包结果\打包与窗口函数\ main.py
–output-dir 这个输出路径自行修改
主图两个控件,一个执行按钮,一个txt控件用于接受py程序
在txt控件中输入:
import win32gui
#下面是我自定的用到win32gui的api程序
from pubunit.windowOperate import findHwnds
hwnd = findHwnds('Chrome','百度一下')
print(hwnd)
import importlib
from pubunit.file import resourcePath
importName='win32gui'
path = resourcePath('\win32\\%s.pyd' % importName)
print(path)
import os
print( os.path.exists(path) )
api = importlib.import_module(importName, path)
print(dir(api))
第一次打包完成之后,没有其他动作,执行提示:
Traceback (most recent call last):
File "D:\打包结果\打包与~1\MAIN~1.DIS\pubDispatch.py", line 26, in run
File "" , line 1, in <module>
ModuleNotFoundError: No module named 'win32gui'
ps: "pubDispatch.py"这个是我程序构造与前面给代码不一样,我采用了三个文件来写测试代码(main.py, pubDispatch.py,UiPubDispatch.ui)
把pycharm导向的win32gui.py拷贝到打包环境下,
import win32gui是成功了,都是里面是一个空壳,调用Find***函数返回值为None。
失败!!!!
由于import win32gui 失败,考虑采用import 替代品试试:
import imp # 替代品1
from ctype import * # 替代品2
import importlib #替代品3
经过测试,
imp的加装方法实验失败,需要后续继续研究。
ctype可以加载,但是没有具体实验,这里就不说了,自行研究。
最终importlib可以加载win32/win32gui.pyd,如下:
path='****/win32/win32gui.pyd' #最好为 绝对路径
#检查路径是否存在
print( os.path.exists(path) ) #
api = importlib.import_module('win32gui', path)
# 打印win32gui的函数
print(dir(api))
# 使用 win32gui的函数进行进一步验证
#hwnd = api.Find****(****)
#print(hwnd)
执行成功!!!!
以上解决办法是没有办法的办法,其实应该还有更好的解决思路,可以进我q群沟通。
提示:路径问题
工作中总是会遇到意想不到的事情发生。我最近需要用到win32gui获取窗口句柄,进行下一步程序操作。以上过程,经过迷茫到有解耗时2天。分享出来供有缘人参考。