Zak
unread,Mar 26, 2013, 2:03:30 PM3/26/13Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to pyins...@googlegroups.com, Gemedet
I had a similar problem with a ctypes DLL. I wrote a library in C, let's
call it my_lib.dll, and it worked fine in --onedir mode. It gave this
same error in --onefile mode (if I recall correctly). The problem was
that when Python tried to load my_lib.dll, it was looking in the wrong
folder. It was looking in the folder holding the --onefile EXE, it was
not looking in the temp directory created by the PyInstaller bootloader.
The example application below shows the solution:
# pyi_ctypes_example.py
#
# By Zak Fallows, 2013-03-26
#
# Point PyInstaller at this file, this is the base script.
#
# PyInstaller has a problem when working with ctypes DLLs in --onefile
mode.
# The problem appears as the following error message:
# WindowsError: [Error 126] The specified module could not be found
# At least, I think that is the error message. I am only 95% sure. The core
# of the problem is that if you freeze the app to create my_app.exe, and
the
# file my_app.exe is in C:\Users\zakf\Downloads\my_app.exe, then the app
# will look for DLLs in C:\Users\zakf\Downloads\, it will NOT look for DLLs
# in C:\Users\zakf\AppData\Local\Temp\_MEI8482\, but this latter directory
# (which is the PyInstaller temp directory) is where the DLL is actually
# located. We must hack the Python so that it looks for the DLL in the temp
# directory, rather than the directory that holds the EXE.
#
# Much of this file is copied from saber/pyi_utils.py
from ctypes import *
import sys
import os.path
def resource_path(relative_path):
"""Returns the path to a resource file in the PyInstaller temp
directory
Arguments:
relative_path String, e.g. "my_lib.dll"
When this file is running in development (i.e. it has not been
packaged by
PyInstaller yet), this function returns a path such as:
C:/Users/zakf/my_app/my_lib.dll
But when this app is running in frozen mode (i.e. it has been
packaged by
PyInstaller and it is now a --onefile executable), the resource
files are
in a very different place. In --onefile frozen mode, the resource
files
are all extracted to a temporary directory. The path to the temporary
directory is given by sys._MEIPASS. Thus, resource_path() will
return the
correct path to the resource file in the temporary directory, such as:
C:/Users/zakf/AppData/Local/Temp/_MEI8482/my_lib.dll
"""
try:
temp_dir_path = sys._MEIPASS
except AttributeError:
temp_dir_path = os.path.abspath(".")
return os.path.join(temp_dir_path, relative_path)
dll_path = resource_path("my_lib.dll")
lib = cdll.LoadLibrary(dll_path)
# Call a function in the DLL:
lib.my_function(c_int(5))
I am also attaching this example as a Python file. It works, all you
need to do is add the DLL.
I don't know if you are using ctypes to call the DLL. If you are using
something else, then it may be having a similar problem. It may not be
looking in the right directory (the temp dir) for the DLL. There are two
possible solutions:
1. Do something like what I did. Tell it where to look.
2. When you distribute your app, tell the users that they need a copy
avbin.dll sitting right next to the EXE. They must keep the EXE and DLL
together, because the EXE will look for the DLL in its home folder. This
is silly but it works. You package with --onefile, but you have to
distribute two files.
Good luck,
Zak Fallows