'Python Ctypes - loading dll throws OSError: [WinError 193] %1 is not a valid Win32 application
I have tried to run an exemple of a python code that gets a function from a library using ctypes. The exemple can be found here. I followed the instruction and beside one minor modification, I have used the exact same code. I have been trying to run this on Windows 10 (64-bit), python 3.7 (64-bit) but got this error message:
Traceback (most recent call last):
File "C:/Users/gifr9302/PycharmProjects/testpytoc/myfunc.py", line 128, in <module>
libmyfunc = npct.load_library('myfunc.dll', os.path.dirname(os.path.abspath(__file__)))
File "C:\Users\gifr9302\AppData\Local\Programs\Python\Python37\lib\site-packages\numpy\ctypeslib.py", line 152, in load_library
return ctypes.cdll[libpath]
File "C:\Users\gifr9302\AppData\Local\Programs\Python\Python37\lib\ctypes\__init__.py", line 431, in __getitem__
return getattr(self, name)
File "C:\Users\gifr9302\AppData\Local\Programs\Python\Python37\lib\ctypes\__init__.py", line 426, in __getattr__
dll = self._dlltype(name)
File "C:\Users\gifr9302\AppData\Local\Programs\Python\Python37\lib\ctypes\__init__.py", line 356, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 n’est pas une application Win32 valide
translated:
OSError: [WinError 193] %1 is not a valid Win32 application
I have tried to create a dll instead of a so file and still got the same error. It would seem it tries to run a 32-bit application on a 64-bit system but I'm not sure why. Can anyone help?
Solution 1:[1]
Mentioning [Python.Docs]: ctypes - A foreign function library for Python (although this doesn't have very much to do with it) just in case.
The underlying error is ERROR_BAD_EXE_FORMAT (193, 0xC1). Check it in [MS.Docs]: System Error Codes (0-499). It's a general Win error (not related to Python). In the current case (related to Python), the exception is a (Python) wrapper over it.
1. The error
The error message is confusing (especially because of %1 placeholder). For more details on that, check [SO]: Why is %1 rarely substituted in “%1 is not a valid Win32 application.”.
This error occurs when Win tries to load what it thinks it's an executable (PE) image (.exe, .dll, ...), but it actually isn't. There's a variety of situations when this is encountered (Googleing the error, would yield lots of results).
There are a bunch of possible reasons for this to happen when the image is loaded from a file (existing and readable, otherwise the error would differ - look at one of the bullets at the answer end):
- Was downloaded and the download is incomplete
- Was (mistakenly) overwritten (or messed up with)
- Is corrupt because of filesystem problem
- Many many more
2 main usecases lead to this error:
- Attempting to run a file which is not an .exe ([SO]: OSError: [WinError 193] %1 is not a valid Win32 application)
- Trying to load a .dll in a process (running .exe). This is the one that I'm going to focus on
Below, it's an example of a dummy executable attempting to load a .dll.
main00.c:
#include <stdio.h>
#include <Windows.h>
int main()
{
DWORD gle = 0;
HMODULE hMod = LoadLibraryA(".\\dll00.dll");
if (hMod == NULL) {
gle = GetLastError();
printf("LoadLibrary failed: %d (0x%08X)\n", gle, gle);
} else {
FreeLibrary(hMod);
}
return gle;
}
Output:
- Note: I'll be reusing this cmd console, even if the copy / paste snippets will be scattered across the answer
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q057187566]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: Build for 064bit (pc064) [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul [prompt]> dir /b code00.py dll00_v0.c main00.c [prompt]> cl /nologo main00.c /link /NOLOGO /OUT:main00_064.exe main00.c [prompt]> :: Creating an invalid .dll [prompt]> echo garbage> dll00.dll [prompt]> dir /b code00.py dll00.dll dll00_v0.c main00.c main00.obj main00_064.exe [prompt]> main00_064.exe LoadLibrary failed: 193 (0x000000C1)
As seen, I created a file dll00.dll containing the text "garbage", so it's a .dll file with invalid contents.
The most common case for this error, is an architecture mismatch:
- 064bit process attempting to load a 032bit .dll
- 032bit process attempting to load a 064bit .dll
In any of the above 2 cases, even if the .dll contains a valid image (for a different architecture), it's still invalid from the current process PoV. For things to run OK, the 2 involved CPU architectures must match (1).
2. Python context
CTypes does the same thing when loading a .dll: it calls [MS.Docs]: LoadLibraryW function on the .dll name.
So this is the exact same case for the Python process where CTypes tries to load the .dll in.
code00.py:
#!/usr/bin/env python3
import sys
import os
import ctypes as ct
DLL_BASE_NAME = "dll00"
def main(*argv):
dll_name = os.path.join(os.path.abspath(os.path.dirname(__file__)), (argv[0] if argv else DLL_BASE_NAME) + ".dll")
print("Attempting to load: [{0:s}]".format(dll_name))
dll00 = ct.CDLL(dll_name)
func00 = dll00.dll00Func00
func00.restype = ct.c_int
res = func00()
print("{0:s} returned {1:d}".format(func00.__name__, res))
if __name__ == "__main__":
print("Python {0:s} {1:03d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
Output:
[prompt]> :: dll00.dll still contains garbage [prompt]> [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.09_test0\Scripts\python.exe" code00.py Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)] 064bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00.dll] Traceback (most recent call last): File "code00.py", line 25, in <module> rc = main(*sys.argv[1:]) File "code00.py", line 14, in main dll00 = ct.CDLL(dll_name) File "c:\Install\pc064\Python\Python\03.07.09\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
Here's an example for (#1) (from above), which attempts all 4 combinations.
dll00_v0.c:
#include <inttypes.h>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# define DLL00_EXPORT_API
#endif
DLL00_EXPORT_API size_t dll00Func00()
{
return sizeof(void*);
}
Output:
[prompt]> :: Still building for pc064 from previous vcvarsall call [prompt]> [prompt]> cl /nologo /DDLL dll00_v0.c /link /NOLOGO /DLL /OUT:dll00_064.dll dll00_v0.c Creating library dll00_064.lib and object dll00_064.exp [prompt]> [prompt]> :: Build for 032bit (pc032) [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x86 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.40 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x86' [prompt]> cl /nologo /DDLL dll00_v0.c /link /NOLOGO /DLL /OUT:dll00_032.dll dll00_v0.c Creating library dll00_032.lib and object dll00_032.exp [prompt]> dir /b *.dll dll00.dll dll00_032.dll dll00_064.dll [prompt]> [prompt]> :: Python pc064 [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.09_test0\Scripts\python.exe" code00.py dll00_064 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)] 064bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_064.dll] dll00Func00 returned 8 Done. [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.09_test0\Scripts\python.exe" code00.py dll00_032 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 bit (AMD64)] 064bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_032.dll] Traceback (most recent call last): File "code00.py", line 25, in <module> rc = main(*sys.argv[1:]) File "code00.py", line 14, in main dll00 = ct.CDLL(dll_name) File "c:\Install\pc064\Python\Python\03.07.09\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application [prompt]> [prompt]> :: Python pc032 [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc032_03.07.09_test0\Scripts\python.exe" code00.py dll00_032 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 bit (Intel)] 032bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_032.dll] dll00Func00 returned 4 Done. [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc032_03.07.09_test0\Scripts\python.exe" code00.py dll00_064 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 bit (Intel)] 032bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_064.dll] Traceback (most recent call last): File "code00.py", line 25, in <module> rc = main(*sys.argv[1:]) File "code00.py", line 14, in main dll00 = ct.CDLL(dll_name) File "c:\Install\pc032\Python\Python\03.07.09\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
3. Bonus
In the above examples, the .dll was loaded "on demand" by explicitly calling LoadLibrary (or LoadLibraryEx).
The other case is when a .exe or .dll depends on (was linked against) another .dll, and loads it automatically when itself is being loaded (although I'm almost certain that LoadLibrary - or maybe a lower level function - is automatically called under the hood on the dependent .dll).
In the example below, dll00*.dll depends on dll01*.dll.
Only exemplifying for 032bit (as this is the current build environment set by previous operation).
dll01.h:
#if defined(_WIN32)
# if defined(DLL01_EXPORTS)
# define DLL01_EXPORT_API __declspec(dllexport)
# else
# define DLL01_EXPORT_API __declspec(dllimport)
# endif
#else
# define DLL01_EXPORT_API
#endif
DLL01_EXPORT_API void dll01Func00();
dll01.c:
#include <stdio.h>
#define DLL01_EXPORTS
#include "dll01.h"
void dll01Func00()
{
printf("In [%s]\n", __FUNCTION__);
}
dll00_v1.c: (modified dll00_v0.c):
#include <inttypes.h>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# define DLL00_EXPORT_API
#endif
#include "dll01.h"
DLL00_EXPORT_API size_t dll00Func00()
{
dll01Func00();
return sizeof(void*);
}
Output:
[prompt]> :: Still building for pc032 from previous vcvarsall call [prompt]> [prompt]> cl /nologo /DDLL dll01.c /link /NOLOGO /DLL /OUT:dll01_032.dll dll01.c Creating library dll01_032.lib and object dll01_032.exp [prompt]> cl /nologo /DDLL dll00_v1.c /link /NOLOGO /DLL /OUT:dll00_032.dll dll00_v1.c Creating library dll00_032.lib and object dll00_032.exp dll00_v1.obj : error LNK2019: unresolved external symbol __imp__dll01Func00 referenced in function _dll00Func00 dll00_032.dll : fatal error LNK1120: 1 unresolved externals [prompt]> [prompt]> cl /nologo /DDLL dll00_v1.c /link /NOLOGO /DLL /OUT:dll00_032.dll dll01_032.lib dll00_v1.c Creating library dll00_032.lib and object dll00_032.exp [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_pc032_03.07.09_test0\Scripts\python.exe" code00.py dll00_032 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 bit (Intel)] 032bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_032.dll] In [dll01Func00] dll00Func00 returned 4 Done. [prompt]> :: Messing up dll01_032.dll [prompt]> echo garbage> dll01_032.dll [prompt]> "e:\Work\Dev\VEnvs\py_pc032_03.07.09_test0\Scripts\python.exe" code00.py dll00_032 Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 bit (Intel)] 032bit on win32 Attempting to load: [e:\Work\Dev\StackOverflow\q057187566\dll00_032.dll] Traceback (most recent call last): File "code00.py", line 25, in <module> rc = main(*sys.argv[1:]) File "code00.py", line 14, in main dll00 = ct.CDLL(dll_name) File "c:\Install\pc032\Python\Python\03.07.09\lib\ctypes\__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
Stating the obvious: Same error would occur if instead of writing garbage data into dll01_032.dll, I would have build it for 064bit, but I chose this variant as it's shorter.
4. Conclusions
Everything that I'll state in each of the next bullets, also applies to the ones that follow it.
- In the examples above, the error occurred when the corruption was in the very .dll being loaded, or in one of its direct dependents (level 1 of indirection). It's not hard to figure out that applying the same principle multiple times, the behavior wouldn't change, so it's valid for any level of indirection.
Imagine a .dll that depends on several other .dlls, and each of those depends in turn on several others, and so on ... . That is called a dependency tree. So no matter where in the tree this error will occur, it will be propagated up to the root node (which is the .dll) - The dependency tree propagation applies to other errors as well. Another one that it's widely encountered is ERROR_MOD_NOT_FOUND (126, 0x7E). It means that the .dll with the specified name (restating: or any other .dll that it (recursively) depends on) was not found.
As a side note, in order to check a .dll (or .exe) dependencies, use Dependency Walker (newer [GitHub]: lucasg/Dependencies) or dumpbin (part of VStudio installation), or as a matter of fact, any tool that is capable of getting PE dependency information - Everything discussed also applies:
- If the .dll is an extension module (.pyd) that is being imported
- If the .dll is being loaded as a result of another module being imported
- Everything discussed also applies to Nix systems, the errors (and corresponding messages), obviously differ
Summarizing:
Make sure that:
- A 064bit process only attempts to load 064bit .dlls
- A 032bit process only attempts to load 032bit .dlls
otherwise, ending up in this (nasty) situation is (almost) certain.
Some real life scenario steps leading here:
Installing a software (Python - in this case)
Installing (creating, building) some kind of plugin (that contains .dlls) for that software (an (extension) module - in this case)
Although in general this kind of check is performed at install time, one needs to check (as already stated), that the CPU architectures of the (above) 2, must match.
If that doesn't happen, change one to match the other, and whenever possible (as there might be some (few) cases when it isn't), aim for 064bit (as it doesn't have many of 032bit's limitations). In this case install (and run) Python 064bit).
Solution 2:[2]
As @CristiFati stated this is occuring because
1)64bit process attempting to load a 32bit .dll
2)32bit process attempting to load a 64bit .dll
Solution:
--> I also encountered the same problem and noticed that my gcc compiler was producing 32-bit compiled files instead of 64-bit.So I changed the compiler which produces 64-bit files.
--> you can check your compiled file(.exe) is 64 or 32 bit by -->right click --> properties--> compatablity -->check the compatibilty mode option-->select the dropdown if you see windows xp in the list then your compiler is producing 32-bit files if you dont see windows xp then your compiler is producing 64-bit files.
Solution 3:[3]
Thanks for the detailed explanation.
But for those who wanted a direct solution. I think you should set up 64-bit python version and the issue will be resolved. It worked for me.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Manoj D Bhat |
Solution 3 | Raoof Naushad |