Python Ctypes - 加载 dll 抛出 OSError:[WinError 193] %1 不是有效的 Win32 应用程序
- 2024-12-18 08:39:00
- admin 原创
- 261
问题描述:
我尝试运行一个使用 ctypes 从库中获取函数的 Python 代码示例。示例可在此处找到。我按照说明进行操作,除了一处小修改外,我使用了完全相同的代码。我一直尝试在 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:Usersgifr9302AppDataLocalProgramsPythonPython37libsite-packages
umpyctypeslib.py", line 152, in load_library
return ctypes.cdll[libpath]
File "C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes__init__.py", line 431, in __getitem__
return getattr(self, name)
File "C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes__init__.py", line 426, in __getattr__
dll = self._dlltype(name)
File "C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes__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 而不是 so 文件,但仍然出现相同的错误。它似乎试图在 64 位系统上运行 32 位应用程序,但我不确定为什么。有人能帮忙吗?
解决方案 1:
提及[Python.Docs]:ctypes - Python 的外部函数库(尽管这与它没有太大关系)以防万一。
底层错误是ERROR_BAD_EXE_FORMAT ( 193 , 0xC1 )。在[MS.Docs]: 系统错误代码 (0-499)中检查它。这是一个常见的Win错误(与Python无关)。在当前情况下(与Python相关),异常是它的( Python )包装器。
1. 错误
错误消息令人困惑(尤其是因为%1占位符)。有关更多详细信息,请查看[SO]:为什么在“%1 不是有效的 Win32 应用程序。”中很少替换 %1。
当Win尝试加载它认为是可执行 ( PE ) 映像 ( .exe、.dll等) 但实际上不是时,就会发生此错误。遇到这种情况的情况多种多样(搜索错误,会得到很多结果)。
当从文件(现有且可读,否则错误会有所不同 -请查看答案末尾的其中一个项目符号)加载图像时,有很多可能的原因导致这种情况发生:
已下载,但下载未完成
被(错误地)覆盖(或弄乱)
由于文件系统问题而损坏
还有更多
有两个主要用例会导致此错误:
尝试运行非.exe文件([SO]: OSError: [WinError 193] %1 不是有效的 Win32 应用程序)
尝试在进程(运行.exe )中加载.dll。这是我要重点关注的一点
下面是一个尝试加载.dll 的虚拟可执行文件的示例(可能需要检查[SO]: 如何构建 libjpeg 9b 的 DLL 版本?(@CristiFati 的回答)以了解有关在Win上构建命令行的详细信息)。
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)
", gle, gle);
} else {
FreeLibrary(hMod);
}
return gle;
}
输出:
注意:我将重复使用这个cmd控制台,即使复制/粘贴片段会分散在答案中
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057187566]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: Build for 064bit (pc064) [prompt]> "c:Installpc032MicrosoftVisualStudioCommunity7VCAuxiliaryBuildcvarsall.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)
如图所示,我创建了一个包含文本“垃圾”的文件dll00.dll,因此它是一个具有无效内容的.dll文件。
此错误最常见的情况是体系结构不匹配:
064 位进程尝试加载032 位 .dll
032 位进程尝试加载064 位 .dll
在上述两种情况下,即使.dll包含有效映像(针对不同的架构),从当前进程PoV来看,它仍然是无效的。要使程序正常运行,所涉及的 2 个CPU架构必须匹配** (1)。
2. Python上下文
CTypes在加载.dll时会执行相同的操作:它会对.dll名称调用[MS.Docs]: LoadLibraryW 函数。因此,这与CTypes尝试加载.dll的Python进程的情况完全相同。
code00.py:
#!/usr/bin/env python
import ctypes as cts
import os
import sys
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" if sys.platform[:3].lower() == "win" else ".so"))
print("Attempting to load: [{:s}]".format(dll_name))
dll00 = cts.CDLL(dll_name)
func00 = dll00.dll00Func00
func00.argtypes = ()
func00.restype = cts.c_int
res = func00()
print("{:s} returned {:d}".format(func00.__name__, res))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}
".format(" ".join(elem.strip() for elem in sys.version.split("
")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("
Done.
")
sys.exit(rc)
注意:检查[SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案),这是使用CTypes(调用函数)时常见的陷阱。
输出:
[prompt]> :: dll00.dll still contains garbage [prompt]> [prompt]> [prompt]> "e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00.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:Installpc064PythonPython.07.09libctypes__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
下面是(#1) (来自上面)的一个例子,它尝试了所有 4 种组合。
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*);
}
输出:
[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:Installpc032MicrosoftVisualStudioCommunity7VCAuxiliaryBuildcvarsall.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:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_064.dll] dll00Func00 returned 8 Done. [prompt]> [prompt]> "e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_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:Installpc064PythonPython.07.09libctypes__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:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_032.dll] dll00Func00 returned 4 Done. [prompt]> [prompt]> "e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_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:Installpc032PythonPython.07.09libctypes__init__.py", line 364, 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上自动调用)。
在下面的例子中,dll00.dll依赖于dll01.dll。
仅针对032bit举例说明(因为这是上一个操作设置的当前构建环境)。
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]
", __FUNCTION__);
}
dll00_v1.c:(修改后的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*);
}
输出:
[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:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_032.dll] In [dll01Func00] dll00Func00 returned 4 Done. [prompt]> :: Messing up dll01_032.dll [prompt]> echo garbage> dll01_032.dll [prompt]> "e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.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:WorkDevStackOverflowq057187566dll00_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:Installpc032PythonPython.07.09libctypes__init__.py", line 364, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application
显而易见的是:如果我不将垃圾数据写入dll01_032.dll ,而是为064bit构建它,则会发生同样的错误,但我选择这个变体是因为它更短。
4. 结论
我在接下来的每个要点中陈述的所有内容也适用于其后的要点。
在上面的例子中,错误发生在损坏发生在正在加载的.dll中,或其直接依赖项之一中(间接级别 1)。不难看出,多次应用相同的原理,行为不会改变,因此它适用于任何间接级别。
想象一个.dll依赖于几个其他.dll,而每个 .dll 又依赖于几个其他 .dll ,依此类推……。这称为依赖树。因此,无论此错误发生在树中的哪个位置,它都会传播到根节点(即.dll)
依赖关系树传播也适用于其他错误。一个例子是ERROR_PROC_NOT_FOUND ( 127 , 0x7F )。查看[SO]: 在 Python 中加载具有依赖项的 DLL (@CristiFati 的答案)了解更多详细信息。
另一个经常遇到的是ERROR_MOD_NOT_FOUND ( 126 , 0x7E )。这意味着未找到具有指定名称 (重述:或它 (递归) 依赖的任何其他.dll* ) 的.dll 。查看[SO]: 无法在 Python 中导入 dll 模块 (@CristiFati 的答案)了解有关该主题的更多详细信息 (也在Python*上下文中)。
附注:为了检查.dll(或.exe)依赖项,请检查[SO]: 使用命令行发现丢失的模块(“DLL 加载失败”错误)(@CristiFati 的答案),或者事实上,使用任何能够获取PE依赖信息的工具
讨论的所有内容也适用:
+ **导入扩展模块**(***.pyd***(*Nix*上的*.so*)时)。没错,*.pyd*只是一个*.dll*(导出*PyInit_**函数)。查看[Python.Docs]: 使用 C 或 C++ 扩展 Python了解更多详细信息
+ 如果由于导入另一个模块(*.pyd*、*.py*等)而加载了*.dll*
所讨论的所有内容也适用于Nix系统,错误(和相应的消息)显然有所不同
5. 总结
确保:
064bit进程仅尝试加载 064bit .dll
032bit进程仅尝试加载 032bit .dll
否则,几乎肯定会陷入这种(糟糕的)境地。
以下是一些现实生活中的步骤:
安装软件(本例中为Python )
为该软件安装(创建、构建)某种插件(包含.dll)(在本例中为(扩展)模块)
尽管通常这种检查是在安装时执行的,但需要检查(如前所述),(上述)2 的CPU体系结构必须匹配。
如果没有发生这种情况,请将一个更改为与另一个匹配,并且只要可能(因为可能存在一些(少数)情况不匹配),就瞄准 064bit(因为它没有032bit的许多限制)。
在这种情况下,安装(并运行)Python 064bit([SO]:如何确定我的 python shell 在 OS X 上是在 32 位还是 64 位模式下执行?(@CristiFati 的回答))。
解决方案 2:
正如 @CristiFati 所说,发生这种情况是因为
1)64位进程尝试加载32位.dll
2)32位进程尝试加载64位.dll
解决方案:
--> 我也遇到了同样的问题,并且发现我的 gcc 编译器生成的是 32 位编译文件而不是 64 位。因此我更换了生成 64 位文件的编译器。
-->您可以通过以下方式检查您的编译文件(.exe)是 64 位还是 32 位:-->右键单击 --> 属性 --> 兼容性 --> 检查兼容模式选项 --> 选择下拉菜单,如果您在列表中看到 Windows XP,则说明您的编译器正在生成 32 位文件,如果您没有看到 Windows XP,则说明您的编译器正在生成 64 位文件。
解决方案 3:
只是为了增加一点保证,我也遇到了同样的问题,但我认为我在 Win10 64 上安装了所有 32 位版本,如果是真的,答案就不适用于我的情况。然而,在检查时,我发现我在等式的 C 端使用了 mingw32 位,在 Python 端使用了 64 位。我安装了 Python 版本 32.10.6,瞧,一切都正常了。因此,对于 Manoj D Bhat 的观点,@CristiFati 的最后一句话在我的情况下是正确的 - 错误的常见原因是:
1)64 位进程尝试加载 32 位 .dll
或者
2)32 位进程尝试加载 64 位 .dll
解决方案 4:
感谢您的详细解释。
但对于那些想要直接解决方案的人来说。我认为你应该设置 64 位 Python 版本,这样问题就会得到解决。对我来说,这很有效。