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 而不是 so 文件,但仍然出现相同的错误。它似乎试图在 64 位系统上运行 32 位应用程序,但我不确定为什么。谁能帮忙?

原文由 Frédéric Girard 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2.7k
1 个回答

提到 [Python.Docs]:ctypes - Python 的外部函数库(尽管这与它没有太大关系)以防万一。

底层错误是 _ERROR_BAD_EXE_FORMAT_ ( 193 , 0xC1 )。在 [MS.Docs]: System Error Codes (0-499) 中查看。这是 一般的 Win 错误(与 Python 无关)。在当前情况下(与 Python 相关),例外是它的 ( Python ) 包装器。

1.错误

错误消息令人困惑(尤其是因为 %1 占位符)。有关详细信息,请查看 [SO]:为什么 %1 很少在“%1 不是有效的 Win32 应用程序”中被替换。 .

Win 尝试加载它认为是可执行 ( PE ) 映像( .exe.dll ……)但实际上不是时,会发生此错误。遇到这种情况的情况多种多样( 谷歌搜索 错误,会产生很多结果)。

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

  • 已下载且下载不完整

  • 被(错误地)覆盖(或搞砸了)

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

  • 还有很多很多

2个主要用例导致此错误:

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

  2. 尝试在进程中加载 .dll (运行 .exe )。 这是我要关注的

下面是一个虚拟可执行文件尝试加载 .dll 的示例(可能需要检查 [SO]: How to build a DLL version of libjpeg 9b? (@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)\n", gle, gle);
    } else {
        FreeLibrary(hMod);
    }
    return gle;
}

输出

  • 注意:我将重复使用这个 cmd 控制台,即使复制/粘贴片段会分散在答案中
> [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)
>
> ```

如图所示,我创建了一个包含文本“ _垃圾_”的文件 _dll00.dll_ ,因此它是一个包含无效内容的 _.dll_ 文件。

此错误最常见的情况是体系结构不匹配:

- **_064 位_ 进程试图加载 _032 位_ _.dll_**

- **_032 位_ 进程试图加载 _064 位_ _.dll_**


在上述两种情况中的任何一种情况下,即使 _.dll_ 包含有效图像(对于不同的体系结构),它在当前进程 _PoV_ 中仍然无效。为了运行 _正常_, **涉及的 2 个 _CPU_ 架构必须匹配**_**(1)**_ 。

### 2\. _Python_ 语境

_CTypes_ 在加载 _.dll_ 时做同样的事情:它在 _.dll_ 名称上调用 [\[MS.Docs\]: LoadLibraryW 函数](https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw)。

所以这与 _CTypes_ 尝试加载 _.dll_ 的 _Python_ 进程完全相同。

_代码00.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)


**输出**:

> ```
>  [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
>
> ```

这是 _**(#1)**_(来自上面)的示例,它尝试了所有 4 种组合。

_dll00_v0.c_ :

#include

#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:\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.奖金

在上面的示例中, _.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 #define DLL01_EXPORTS #include “dll01.h”

void dll01Func00() { printf(“In [%s]\n”, FUNCTION); }


_dll00_v1.c_ :(修改后 _的 dll00_v0.c_ ):

#include

#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:\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

说明显而易见:如果我没有将垃圾数据写入 _dll01032.dll 而不是将其构建为 064bit ,则会发生同样的错误,但我选择了这个变体,因为它更短。

4。结论

我将在接下来的每个项目符号中陈述的所有内容也适用于它后面的项目符号。

  • 在上面的例子中,当损坏发生在正在加载的 .dll 中,或者它的一个直接依赖项(间接级别 1)中时,就会发生错误。不难发现多次应用相同的原则,行为不会改变,所以它对任何间接级别都有效。

想象一个 .dll 依赖于其他几个 .dll ,而每个 .dll 又依赖于其他几个,依此类推……。这就是所谓的 依赖树。所以无论 这个错误发生在树的哪个位置,它都会传播到根节点(即 .dll

  • 依赖树传播也适用于其他错误。另一个 广泛遇到 的错误是 _ERROR_MOD_NOT_FOUND_ ( 126 , 0x7E )。这意味着找不到具有指定名称的 .dllrestating: 或它(递归)依赖的任何其他 .dll )。检查 [SO]: Can’t import dll module in Python(@CristiFati 的回答) 以获取有关该主题(也在 Python 上下文中)的更多详细信息。

作为旁注,为了检查 .dll (或 .exe )依赖性,检查 [SO]: Discover missing module using command-line (“DLL load failed” error) (@CristiFati’s answer) ,或者作为一个问题事实上,使用任何能够获取 PE 依赖信息的工具

  • 讨论的所有内容也适用:

    • 如果 .dll 是正在导入的扩展模块 ( .pyd )

    • 如果由于导入另一个模块而加载 .dll

  • 讨论的所有内容也适用于 Nix 系统,错误(和相应的消息)明显不同

5.总结

确保:

  • 064 位 进程 仅尝试加载 064 位 .dll

  • 032 位 进程 仅尝试加载 032 位 .dll s

否则,(几乎)肯定会陷入这种(恶劣的)情况。

此处引导的一些现实生活场景步骤:

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

  2. 为该软件安装(创建,构建)某种插件(包含 .dll s)( 一个(扩展)模块- 在这种情况下)

虽然通常这种检查是在安装时执行的,但需要检查(如前所述),(以上)2 的 CPU 架构 必须匹配

如果没有发生, 请更改一个以匹配另一个,并尽可能(因为可能有一些(少数)情况不是), 瞄准 064bit (因为它没有很多 032bit 的限制).在这种情况下安装(并运行) Python 064bit

原文由 CristiFati 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题