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 r...

问题描述:

我尝试运行一个使用 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等) 但实际上不是时,就会发生此错误。遇到这种情况的情况多种多样(搜索错误,会得到很多结果)。

当从文件(现有且可读,否则错误会有所不同 -请查看答案末尾的其中一个项目符号)加载图像时,有很多可能的原因导致这种情况发生:

  • 已下载,但下载未完成

  • 被(错误地)覆盖(或弄乱)

  • 由于文件系统问题而损坏

  • 还有更多

有两个主要用例会导致此错误:

  1. 尝试运行非.exe文件([SO]: OSError: [WinError 193] %1 不是有效的 Win32 应用程序)

  2. 尝试在进程(运行.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:Installpc032MicrosoftVisualStudioCommunity7VCAuxiliaryBuildcvarsall.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:Installpc032MicrosoftVisualStudioCommunity7VCAuxiliaryBuildcvarsall.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

否则,几乎肯定会陷入这种(糟糕的)境地。

以下是一些现实生活中的步骤:

  1. 安装软件(本例中为Python )

  2. 为该软件安装(创建、构建)某种插件(包含.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 版本,这样问题就会得到解决。对我来说,这很有效。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用