首页 > 解决方案 > Python Ctypes - 加载 dll 引发 OSError:[WinError 193] %1 不是有效的 Win32 应用程序

问题描述

我试图运行一个使用 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:\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 位应用程序,但我不知道为什么。任何人都可以帮忙吗?

标签: pythoncwindowsdllctypes

解决方案


提到 [ 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 应用程序”。</a>。

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

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

  • 已下载,下载不完整
  • 被(错误地)覆盖(或搞砸了)
  • 由于文件系统问题而损坏
  • 还有很多很多

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

  1. 尝试运行不是.exe的文件([SO]: OSError: [WinError 193] %1 不是有效的 Win32 应用程序
  2. 尝试在进程中加载​​ .dll(运行.exe)。这是我要重点关注的一个

下面是一个尝试加载.dll的虚拟可执行文件的示例。

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
[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 函数。因此,这与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) (from above)的示例,它尝试了所有 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 064bit 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
[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 064bit
[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 032bit
[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.奖金

在上面的示例中,通过显式调用LoadLibrary(或LoadLibraryEx ) “按需”加载.dll。另一种情况是.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]\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*);
}

输出

[prompt]> :: Still building for 032bit 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依赖于其他几个.dll,而其中的每一个又依赖于其他几个,依此类推......。这称为依赖树。因此,无论在树中的哪个位置发生此错误,它都会传播到根节点(即.dll
  • 依赖树传播也适用于其他错误。另一个广泛遇到的是ERROR_MOD_NOT_FOUND ( 126 , 0x7E )。这意味着未找到具有指定名称的.dll (重述:或它(递归)依赖的任何其他.dll)。
    作为旁注,为了检查.dll(或.exe)依赖关系,请使用Dependency Walker(较新的[GitHub]:lucasg/Dependencies)或dumpbinVStudio安装的一部分),或者事实上,任何工具能够得到PE依赖信息
  • 讨论的所有内容也适用:
    • 如果.dll是正在导入的扩展模块 ( .pyd )
    • 如果由于导入另一个模块而加载.dll
  • 讨论的所有内容也适用于Nix系统,错误(和相应的消息)明显不同

推荐阅读