Awesome, thanks Zak! It *was *using ctypes, so calling LoadLibrary manually fixed it.
G On Tue, Mar 26, 2013 at 11:03 AM, Zak <[email protected]> wrote: > 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 > -- You received this message because you are subscribed to the Google Groups "PyInstaller" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/pyinstaller?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
