Проблема pyinstaller и ctypes
Написал код для дистанционного управления устройством через телеграм бота, скомпилировал в exe при помощи pyinstaller -F -w bot.py, а при попытке открыть exe файл, я получаю ошибку. Нужный DLL как и полагается находится ровно в той же папке что и exe файл Текст ошибки и код ниже:
import ctypes
import os
import telebot
CWD = os.path.dirname(__file__)
dllpath = os.path.join(CWD, "FCS.dll")
FuncsDLL = ctypes.CDLL(dllpath)
sumF = FuncsDLL.addNum
sumF.argtypes = [ctypes.c_int]
sumF.restype = ctypes.c_int
off = FuncsDLL.off
off.argtypes = []
off.restype = None
fmsbx = FuncsDLL.fmsgbox
fmsbx.argtypes = []
fmsbx.restype = None
lock = FuncsDLL.sclock
lock.argtypes = []
lock.restype = None
hideAll = FuncsDLL.sclock
hideAll.argtypes = []
hideAll.restype = None
bot = telebot.TeleBot("token")
last_message_id = 0
pref = "v1 "
@bot.message_handler(func=lambda msg: msg.message_id > last_message_id)
def handler(msg):
global last_message_id
last_message_id = msg.message_id
if msg.text == pref+"off":
off()
if msg.text == pref+"error":
fmsbx()
if msg.text == pref+"lock":
lock()
if msg.text == pref+"hideAll":
hideAll()
bot.polling(none_stop=True)
Ошибка:
Traceback (most recent call last):
File "PyInstaller\loader\pyimod03_ctypes.py", line 53, in __init__
File "ctypes\__init__.py", line 379, in __init__
FileNotFoundError: Could not find module 'C:\Users\DimoNULL\AppData\Local\Temp\_MEI6122\FCS.dll' (or one of its dependencies). Try using the full path with constructor syntax.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "tele.py", line 6, in <module>
File "PyInstaller\loader\pyimod03_ctypes.py", line 55, in __init__
pyimod03_ctypes.install.<locals>.PyInstallerImportError: Failed to load dynlib/dll 'C:\\Users\\DimoNULL\\AppData\\Local\\Temp\\_MEI6122\\FCS.dll'. Most likely this dynlib/dll was not found when the application was frozen.
Ответы (1 шт):
Когда вы запускаете свой скрипт (не упакованный
), путь к текущему рабочему каталогу (CWD
) будет тем каталогом, в котором находится ваш скрипт. В моём случае, скрипт запускается из каталога "C:\Users\Amgarak\Desktop"
, поэтому CWD
будет равен этому пути.
import os
print(__file__) # C:\Users\Amgarak\Desktop\133.py
CWD = os.path.dirname(__file__)
print(CWD) # C:\Users\Amgarak\Desktop
Но если упаковать свой скрипт в исполняемый файл, то при запуске exe
он будет создавать временный каталог для распаковки всех необходимых файлов, включая сам скрипт и любые другие файлы, которые он использует. Путь к этому временному каталогу будет выглядеть примерно так: "C:\Users\Amgarak\AppData\Local\Temp_MEI173362"
.
import os
print(__file__) # C:\Users\Amgarak\AppData\Local\Temp\_MEI202722\133.py
CWD = os.path.dirname(__file__)
print(CWD) # C:\Users\Amgarak\AppData\Local\Temp\_MEI202722\
Соответственно скрипт запускается из временного каталога, CWD
будет указывать на этот временный каталог, а не на каталог, где лежит exe
. Поэтому при попытке создать путь к файлу "FCS.dll"
с помощью os.path.dirname
, будет указывать на каталог временных файлов, а не на каталог c exe
.
print(sys.executable) # C:\Users\Amgarak\Desktop\output\133.exe
exe_dir = os.path.dirname(sys.executable)
print(exe_dir) # C:\Users\Amgarak\Desktop\output
Таким образом можно получить путь, где лежит непосредственно наш exe
. Впрочем, можно воспользоваться и относительным путем:
with open('output.txt', 'r') as file:
value = file.read()
print(value) # Python generation!
Мой файл 'output.txt'
лежит в той же директории что и запускаемый exe
.
Так что, если dll
в той же папке что и exe
, можете использовать имя dll
без указания пути:
FuncsDLL = ctypes.CDLL("FCS.dll")