Python Ctypes - 加载 dll 抛出 OSError: [WinError 193] %1 不是有效的 Win32 应用程序

2023-12-09

我尝试运行一个 python 代码示例,该代码使用 ctypes 从库中获取函数。例子可以找到here。我按照说明进行操作,除了一处小的修改之外,我使用了完全相同的代码。我一直在尝试在 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 位应用程序,但我不确定为什么。有人可以帮忙吗?


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

根本错误是ERROR_BAD_EXE_FORMAT (193, 0xC1)。检查一下[MS.Docs]:系统错误代码 (0-499)。它是general Win error(不相关Python)。在目前的情况下(与Python),例外是 (Python)包装在它上面。

1. 错误

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

当出现此错误时Win尝试加载它认为是可执行文件的内容(PE) 图像 (.exe, .dll,...),但实际上并非如此。遇到这种情况的情况有很多种(Google错误,会产生很多结果)。

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

  • 已下载且下载不完整

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

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

  • 还有很多很多

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

  1. 试图运行一个不是.exe ([SO]: OSError: [WinError 193] %1 不是有效的 Win32 应用程序)

  2. 正在尝试加载一个.dll在一个进程中(运行.exe). 这是我要重点关注的

下面是一个虚拟可执行文件尝试加载.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)\n", gle, gle);
    } else {
        FreeLibrary(hMod);
    }
    return gle;
}

Output:

  • Note: 我会重复使用这个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包含文本“garbage”,所以这是一个.dll文件包含无效内容。

此错误最常见的情况是架构不匹配:

  • 064bit进程尝试加载032bit .dll

  • 032bit进程尝试加载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加载时做同样的事情.dll: 它调用[MS.Docs]:LoadLibraryW 函数 on the .dll name.
所以这与以下情况完全相同Python过程在哪里CTypes尝试加载.dll in.

代码00.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}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Note: check [SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案)与使用时常见的陷阱CTypes(调用函数)。

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

在上面的例子中,.dll通过显式调用“按需”加载加载库 (or 加载库Ex).
另一种情况是当.exe or .dll依赖于(链接到)另一个.dll,并在加载自身时自动加载它(尽管我几乎可以肯定加载库- 或者可能是一个较低级别的函数 - 在依赖项的后台自动调用.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]\n", __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*);
    }
    

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

显而易见:如果不将垃圾数据写入dll01_032.dll,我会为064bit,但我选择了这个变体,因为它更短。

4。结论

我将在接下来的每个项目符号中说明的所有内容也适用于其后的项目符号。

  • 在上面的例子中,当损坏发生在最开始的时候,错误就发生了。.dll正在加载,或者在其直接依赖项之一中(间接级别 1)。不难看出,多次应用相同的原则,行为不会改变,因此它对于任何级别的间接都是有效的。
    想象一个.dll这取决于其他几个.dlls,其中每一个又依赖于其他几个,依此类推……。这就是所谓的依赖树。所以不管在树中的哪个位置会发生此错误,它将传播到根节点(哪一个是.dll)

  • 依赖树传播也适用于其他错误。另一种是它广泛遇到的 is ERROR_MOD_NOT_FOUND (126, 0x7E)。这意味着.dll具有指定的名称 (重述:或任何其他.dll它(递归地)取决于) 没找到。查看[SO]:无法在 Python 中导入 dll 模块(@CristiFati 的回答)有关该主题的更多详细信息(也在Python语境)。
    作为旁注,为了检查.dll (or .exe) 依赖关系,检查[SO]:使用命令行发现丢失的模块(“DLL加载失败”错误)(@CristiFati的答案),或者事实上,使用任何能够获得的工具PE依赖信息

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

    • 导入扩展模块时 (.pyd (.so on Nix))。没错,就是.pyd只是一个.dll(它出口一个PyInit_*功能)。查看[Python.Docs]:使用 C 或 C++ 扩展 Python更多细节

    • If the .dll正在作为另一个模块的结果被加载(.pyd, .py, ...) 正在导入

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

5. 总结

确保:

  • A 064bit过程仅尝试加载 064bit .dlls

  • A 032bit过程仅尝试加载 032bit .dlls

否则,(几乎)肯定会陷入这种(令人讨厌的)情况。

一些现实生活中的场景步骤如下:

  1. 安装软件(Python- 在这种情况下)

  2. 安装(创建、构建)某种插件(包含.dlls) 对于该软件 (一个(扩展)模块- 在这种情况下)

尽管通常这种检查是在安装时执行的,但需要检查(如前所述)CPU(上面)2的架构,必须匹配.
如果那不发生的话更改一个以匹配另一个,并且只要有可能(因为可能有一些(少数)情况并非如此),目标是064位(因为它没有很多032bit的限制)。
在这种情况下,安装(并运行)Python 064位 ([SO]:如何确定我的 python shell 是在 OS X 上以 32 位还是 64 位模式执行? (@CristiFati 的回答)).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python Ctypes - 加载 dll 抛出 OSError: [WinError 193] %1 不是有效的 Win32 应用程序 的相关文章

随机推荐