win32api?
If you are seeing this error when importing any of the pywin32 packages, eg win32api or win32gui etc. then it is likely the cause is a bug in the version of pywin32 you are using. To fix it install version 228 of pywin32 by running the following:
pip install --force-reinstall "pywin32==228"
A bug was introduced in version 300 of pywin32 that causes this error. The problem has been fixed and should be included in the next release of pywin32, but for now you will need to use version 228 or an earlier release of pywin32.
When importing a compiled Python extension module (a .pyd file), if any DLL dependencies can't be loaded you will see the error message:
DLL load failed: The specified module could not be found
When a Python extension module is compiled it may depend on some additional libraries called DLLs, or Dynamic Link Libraries. If these DLLs can't be found when trying to load the Python extension module then the module won't be able to be imported and that is what this error is telling you.
When loading a Python extension module, any DLL dependencies must either be located in the same folder as the Python extension module, or in a folder included in the PATH environment variable.
Typically any DLL dependencies are installed in the same folder as the .pyd Python extension module. If you are using Anaconda and have used conda to install the Python extension then it may have installed the DLL dependencies into the "Library/bin" folder in the conda environment. The "Library/bin" folder is added to your PATH automatically when PyXLL starts.
If the DLL dependencies are missing then it can point to a problem that occured when installing the package. Uninstalling the package and re-installing it can help if this is the case. It is important not to install a package using both pip and conda as this can result in two different versions being installed which could conflict. Try uninstalling with both pip and conda before re-installing using only one of pip or conda to make sure.
If you are having trouble with a Python extension module you have built yourself that has not been installed via pip or conda, you will need to check any dependency DLLs are present in the correct place so they can be found.
Finding DLL Dependencies
To determine what DLL dependencies a Python extension module has you will need to use a tool like depends.exe, which can be downloaded from http://www.dependencywalker.com/. Another good option is CFF Explorer, included in NT Explorer Suite which can be downloaded from https://ntcore.com/?page_id=388.
Dependency Walker can be very slow as it looks for all indirect dependencies when opening a file, so if you are struggling to load your .pyd file using Dependency Walker try CFF Explorer instead.
Here we can see using CFF Explorer all the dependencies of the QtCore.pyd Python extension module. Qt5Core.dll hasn't been found in the same folder as QtCore.pyd or on the PATH, but in this case it should exist in Anaconda's "Library\bin" folder and so it will be loaded from there.
Checking the PATH environment variable
If all the DLL depenedencies are present but the extension module still won't load it's time to check what the PATH environment variable is set to.
Assuming your Python module imports in a normal Python prompt, you can compare the PATH that Python prompt is using against the PATH that Excel is using.
In a Python prompt check the PATH by doing the following:
import os
for path in os.environ["PATH"].split(";"):
print(path)
This will print out every folder in the current PATH that the Python session is using. If the Python extension module is importing correctly in this Python prompt but not in Excel then it's likely that the PATH is different when running in Excel.
To check the PATH in Excel, create a new Python module (e.g. check_path.py) and add it to the list of modules in your pyxll.cfg file, updating pythonpath as well if necessary. Add the following code to your module to create a worksheet function for returning all the folder in the PATH:
from pyxll import xl_func
import os
@xl_func(auto_resize=True)
def check_path():
return os.environ["PATH"].split(";")
In Excel, reload PyXLL or restart Excel and then call this new function by typing =check_path() into a cell. This will return all the folders in the PATH currently set in Excel.
By comparing the two lists of folders you can see if any are missing in Excel that are present in Python. If any of those missing folders contain the DLL dependencies then that explains why the Python extension module can't be loaded in Excel.
Setting the PATH environment variable
The PATH is set as an environment variable on your PC. To change it for Excel, there's no need to change it globally as you can set it in the pyxll.cfg file.
The PATH environment varibable is a list of folders separated by ";". To add a new folder to the list you can add the following to your pyxll.cfg file:
[ENVIRONMENT]
PATH = C:\Path\To\Add;%(PATH)s
Note that after "C:\Path\To\Add" is ";" followed by %(PATH)s. This gets substituted for the current value of PATH before setting the new value, so the new PATH value is the additional folder followed by the previous PATH value.
See the following pages from the documentation for more information:
- https://www.pyxll.com/docs/userguide/config.html#environment-variables
- https://www.pyxll.com/docs/userguide/config.html#environment-variables-in-configuration-values
Still unable to find what DLL is missing?
If you can't figure out why your Python extension module is still not loading you can use Process Monitor (download from https://docs.microsoft.com/en-us/sysinternals/downloads/procmon) to see exactly what DLLs are being looked for an what folders are being looked in. This can be a fairly tricky process if you're not already used to debugging these types of problems, but this is a very useful last resort to know about.
To start with remove all the modules from your pyxll.cfg file, and replace them with just the Python extension module that you're having problems with. This will make it easier to see what's going wrong by removing the noise from importing the other modules.
Start Excel as normal and then start Process Monitor. Use the sights icon to filter the events just to the Excel process by clicking and dragging the sights icon onto the Excel window.
If you have an idea what DLL you're looking for, you can use the filters to narrow down the events further to only include certain filenames (e.g. If you were having trouble with loading the PyQt5 pacakge, you could filter on file names containing "qt", or you could filter to only show files ending with ".dll").
Once you've got Process Monitor only looking at events from Excel and have configured any filters you will be able to see everything Excel is doing when loading Python modules.
Clear the Process Monitor events window by pressing the "Clear" button, and then go back to Excel and reload the PyXLL add-in. You will see lots more events appear in Process Monitor, and those events will tell you what's being attempted to be loaded and where it's looking.
In the screenshow above, Excel is looking for a file named "Qt5Core.dll" on the system PATH. Usually this would be installed in the "Library\bin" folder (if using Anaconda), but here you can see that Excel is looking for it there but not finding it. This tells us that the Qt5Core.dll file is missing and we need to install it before we can import the Python extension module that depends on it.