Python Ctypes - многомерные массивы: загрузка dll-бросков OSError: [WinError 193] %1 не является допустимым приложением Win32
Я попытался запустить пример кода Python, который получает функцию из библиотеки, используя ctypes. Пример можно найти здесь. Я следовал инструкции и, кроме одной незначительной модификации, я использовал точно такой же код. Я пытался запустить это на Windows 10 (64-разрядная версия), Python 3.7 (64-разрядная версия), но получил это сообщение об ошибке:
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
в переводе:
OSError: [WinError 193] %1 is not a valid Win32 application
Я попытался создать DLL вместо файла так и все еще получил ту же ошибку. Казалось бы, он пытается запустить 32-разрядное приложение в 64-разрядной системе, но я не уверен, почему. Кто-нибудь может помочь?
4 ответа
Упоминание [Python 3.Docs]: ctypes - библиотека сторонних функций для Python (хотя это не имеет к этому никакого отношения) на всякий случай.
Это оболочка (Python) поверх ERROR_BAD_EXE_FORMAT (193, 0xC1). Проверьте это в [MS.Docs]: Коды системных ошибок (0-499).
1. Ошибка
Сообщение об ошибке сбивает с толку (особенно из-за заполнителя %1). Подробнее об этом см. В [SO]: почему%1 редко подставляется в "%1 не является допустимым приложением Win32".
Эта ошибка возникает, когда Win пытается загрузить то, что считает исполняемым образом (.exe, .dll,...), но на самом деле это не так. Существует множество ситуаций, когда это встречается (Google с ошибкой даст много результатов).
Существует множество возможных причин, по которым это может произойти, когда изображение загружается из файла (существующего и читаемого, в противном случае ошибка будет отличаться - посмотрите на один из маркеров в конце):
- Был загружен и загрузка не завершена
- Поврежден из-за проблемы с файловой системой
- Был ошибочно перезаписан
2 основных варианта использования приводят к этой ошибке:
- Попытка запустить файл, который не является .exe ( [SO]: OSError: [WinError 193]%1 не является допустимым приложением Win32)
- Попытка загрузить .dll в процессе (работает .exe). Это тот, на котором я собираюсь сосредоточиться
Ниже приведен пример, где фиктивный исполняемый файл пытается загрузить DLL.
code0.c:
#include <stdio.h>
#include <Windows.h>
int main() {
DWORD gle = 0;
HMODULE hMod = LoadLibraryA(".\\dll0.dll");
if (hMod == NULL) {
gle = GetLastError();
printf("LoadLibrary failed: %d (0x%08X)\n", gle, gle);
} else {
FreeLibrary(hMod);
}
return gle;
}
Выход:
- Примечание: я буду использовать эту консоль cmd, даже если фрагменты копирования / вставки будут разбросаны по ответу
[cfati@CFATI-5510-0:e:\Work\Dev\Stackru\q057187566]> sopr.bat *** Set shorter prompt to better fit when pasted in Stackru (or other) pages *** [prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.14 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x64' [prompt]> dir /b code0.c dll0.c script0.py [prompt]> cl /nologo code0.c /link /NOLOGO /OUT:code0_064.exe code0.c [prompt]> :: Creating an invalid dll [prompt]> echo garbage> dll0.dll [prompt]> dir /b code0.c code0.obj code0_064.exe dll0.c dll0.dll script0.py [prompt]> code0_064.exe LoadLibrary failed: 193 (0x000000C1)
Как видно, я создал файл dll0.dll, содержащий текст " мусор ", поэтому это файл .dll с недопустимым содержимым.
Наиболее распространенным случаем для этой ошибки является несоответствие архитектуры:
- 64-битный процесс пытается загрузить 32- битный.dll
- 32-битный процесс пытается загрузить 64- битный.dll
В любом из вышеупомянутых 2 случаев, даже если DLL- файл содержит допустимое изображение для другой архитектуры, он по-прежнему недействителен из текущего процесса PoV. Чтобы все работало нормально, 2 задействованные архитектуры ЦП должны совпадать с 1.
2. Контекст Python
ctypes делает то же самое при загрузке .dll: она вызывает функцию [MS.Docs]: LoadLibraryW для имени .dll.
Так что это точно такой же случай для процесса Python, где ctypes пытается загрузить .dll в.
script0.py:
#!/usr/bin/env python3
import sys
import os
import ctypes
DLL_BASE_NAME = "dll0"
def main(args):
dll_name = os.path.join(os.path.abspath(os.path.dirname(__file__)), (args[0] if args else DLL_BASE_NAME) + ".dll")
print("Attempting to load: [{0:s}]".format(dll_name))
dll0 = ctypes.CDLL(dll_name)
func0 = dll0.dll0Func0
func0.restype = ctypes.c_int
res = func0()
print("{0:s} returned {1:d}".format(func0.__name__, res))
if __name__ == "__main__":
print("Python {0:s} {1:d}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))
main(sys.argv[1:])
print("\nDone.")
Выход:
[prompt]> :: dll0.dll still contains garbage [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script0.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0.dll] Traceback (most recent call last): File "script0.py", line 24, in <module> main(sys.argv[1:]) File "script0.py", line 14, in main dll0 = ctypes.CDLL(dll_name) File "c:\install\x64\python\python\03.07.03\Lib\ctypes\__init__.py", line 356, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
Вот пример для 1 (сверху), который пытается все 4 комбинации.
dll0.c:
#include <inttypes.h>
#if defined(_WIN32)
# define DLL0_EXPORT_API __declspec(dllexport)
#else
# define DLL0_EXPORT_API
#endif
DLL0_EXPORT_API size_t dll0Func0() {
return sizeof(void*);
}
Выход:
[prompt]> :: Still building for 64bit from previous vcvarsall call [prompt]> [prompt]> cl /nologo /DDLL dll0.c /link /NOLOGO /DLL /OUT:dll0_064.dll dll0.c Creating library dll0_064.lib and object dll0_064.exp [prompt]> [prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x86 ********************************************************************** ** Visual Studio 2017 Developer Command Prompt v15.9.14 ** Copyright (c) 2017 Microsoft Corporation ********************************************************************** [vcvarsall.bat] Environment initialized for: 'x86' [prompt]> cl /nologo /DDLL dll0.c /link /NOLOGO /DLL /OUT:dll0_032.dll dll0.c Creating library dll0_032.lib and object dll0_032.exp [prompt]> dir /b *.dll dll0.dll dll0_032.dll dll0_064.dll [prompt]> [prompt]> :: Python 64bit [prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script0.py dll0_064 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_064.dll] dll0Func0 returned 8 Done. [prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script0.py dll0_032 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_032.dll] Traceback (most recent call last): File "script0.py", line 24, in <module> main(sys.argv[1:]) File "script0.py", line 14, in main dll0 = ctypes.CDLL(dll_name) File "c:\install\x64\python\python\03.07.03\Lib\ctypes\__init__.py", line 356, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application [prompt]> [prompt]> :: Python 32bit [prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py dll0_032 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_032.dll] dll0Func0 returned 4 Done. [prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py dll0_064 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_064.dll] Traceback (most recent call last): File "script0.py", line 24, in <module> main(sys.argv[1:]) File "script0.py", line 14, in main dll0 = ctypes.CDLL(dll_name) File "c:\install\x86\python\python\03.07.03\Lib\ctypes\__init__.py", line 356, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
3. Бонус
В приведенных выше примерах .dll был загружен "по требованию" путем явного вызова LoadLibrary (или LoadLibraryEx).
Другой случай, когда .exe или .dll зависит от (был связан с) другого .dll, и он загружает его автоматически, он загружается (хотя я почти уверен, что LoadLibrary - или, возможно, функция более низкого уровня - вызывается автоматически на зависимом .dll).
В приведенном ниже примере dll0*.dll зависит от dll1 *.dll. Только пример для 32-битной системы (поскольку это текущая среда сборки, установленная предыдущей операцией).
dll1.h:
#if defined(_WIN32)
# if defined(DLL1_EXPORTS)
# define DLL1_EXPORT_API __declspec(dllexport)
# else
# define DLL1_EXPORT_API __declspec(dllimport)
# endif
#else
# define DLL1_EXPORT_API
#endif
DLL1_EXPORT_API void dll1Func0();
dll1.c:
#include <stdio.h>
#define DLL1_EXPORTS
#include "dll1.h"
void dll1Func0() {
printf("In [%s]\n", __FUNCTION__);
}
dll0.c (модифицированный):
#include <inttypes.h>
#if defined(_WIN32)
# define DLL0_EXPORT_API __declspec(dllexport)
#else
# define DLL0_EXPORT_API
#endif
#include "dll1.h"
DLL0_EXPORT_API size_t dll0Func0() {
dll1Func0();
return sizeof(void*);
}
Выход:
[prompt]> :: Still building for 32bit from previous vcvarsall call [prompt]> [prompt]> cl /nologo /DDLL dll1.c /link /NOLOGO /DLL /OUT:dll1_032.dll dll1.c Creating library dll1_032.lib and object dll1_032.exp [prompt]> cl /nologo /DDLL dll0.c /link /NOLOGO /DLL /OUT:dll0_032.dll dll0.c Creating library dll0_032.lib and object dll0_032.exp dll0.obj : error LNK2019: unresolved external symbol __imp__dll1Func0 referenced in function _dll0Func0 dll0_032.dll : fatal error LNK1120: 1 unresolved externals [prompt]> [prompt]> cl /nologo /DDLL dll0.c /link /NOLOGO /DLL /OUT:dll0_032.dll dll1_032.lib dll0.c Creating library dll0_032.lib and object dll0_032.exp [prompt]> [prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py dll0_032 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_032.dll] In [dll1Func0] dll0Func0 returned 4 Done. [prompt]> :: Messing up dll1_032.dll [prompt]> echo garbage> dll1_032.dll [prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py dll0_032 Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32 Attempting to load: [e:\Work\Dev\Stackru\q057187566\dll0_032.dll] Traceback (most recent call last): File "script0.py", line 24, in <module> main(sys.argv[1:]) File "script0.py", line 14, in main dll0 = ctypes.CDLL(dll_name) File "c:\install\x86\python\python\03.07.03\Lib\ctypes\__init__.py", line 356, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
Утверждение очевидное: та же ошибка произошла бы, если бы вместо записи данных мусора в dll1_032.dll я собрал ее для 64-битной версии, но я выбрал этот вариант, так как он короче.
4. Выводы
Все, что я изложу в каждой из следующих пуль, относится и к тем, которые следуют за ним.
- В приведенных выше примерах ошибка возникала, когда повреждение происходило в самой загружаемой DLL или в одной из ее прямых зависимостей (уровень 1 косвенности). Нетрудно понять, что, применяя один и тот же принцип несколько раз, поведение не изменится, поэтому оно справедливо для любого уровня косвенности.
Представьте себе .dll, которая зависит от нескольких других .dll, и каждая из них, в свою очередь, зависит от нескольких других, и так далее.... Это называется деревом зависимостей. Поэтому независимо от того, где в дереве произойдет эта ошибка, она будет распространена до корневого узла. - Распространение дерева зависимостей относится и к другим ошибкам. Еще одна широко распространенная проблема - ERROR_MOD_NOT_FOUND (126, 0x7E). Это означает, что .dll с указанным именем не найден.
- Все обсуждаемое также относится:
- Если .dll является модулем расширения (.pyd), который импортируется
- Если .dll загружается в результате импорта другого модуля
- Все обсуждаемое также относится к системам Nix, ошибки (и соответствующие сообщения), очевидно, отличаются
Как заявил @CristiFati, это происходит потому, что
1)64-битный процесс пытается загрузить 32-битный .dll
2)32-битный процесс пытается загрузить 64-битный .dll
Решение:
-> Я также столкнулся с той же проблемой и заметил, что мой компилятор gcc создает 32-битные скомпилированные файлы вместо 64-битных, поэтому я изменил компилятор, который создает 64-битные файлы.
-> вы можете проверить, что ваш скомпилированный файл (.exe) - 64 или 32-битный -> щелкните правой кнопкой мыши -> свойства -> совместимость -> проверьте параметр режима совместимости -> выберите раскрывающийся список, если вы видите окна xp в списке, то ваш компилятор создает 32-битные файлы, если вы не видите Windows XP, значит, ваш компилятор создает 64-битные файлы.
Просто чтобы добавить немного уверенности в том, чего это стоит, я тоже столкнулся с той же проблемой, но думал, что у меня 32-битные версии всего, что установлено на Win10 64, и если это правда, ответ не будет применяться к моим обстоятельствам. Однако при проверке я обнаружил, что использую mingw32 бит на стороне C уравнения и 64 бит на стороне Python. Я установил Python версии 32.10.6 и вуаля, все заработало. Итак, во-вторых, Манодж Д. Бхат, последнее утверждение @CristiFati было правильным в моем случае - обычная причина ошибки:
1)64-битный процесс пытается загрузить 32-битную .dll
или
2)32-битный процесс пытается загрузить 64-битную .dll
Спасибо за подробное объяснение.
Но для тех, кто хотел прямого решения. Я думаю, вам следует установить 64-битную версию Python, и проблема будет решена. Это сработало для меня.