本文介绍了Python Ctypes - 加载 dll 引发 OSError: [WinError 193] %1 不是有效的 Win32 应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试运行一个使用 ctypes 从库中获取函数的 Python 代码示例.该示例可以在此处找到.我按照说明进行操作,除了一个小的修改外,我还使用了完全相同的代码.我一直在尝试在 Windows 10(64 位)、python 3.7(64 位)上运行它,但收到此错误消息:

回溯(最近一次调用最后一次): 中的文件C:/Users/gifr9302/PycharmProjects/testpytoc/myfunc.py",第 128 行libmyfunc = npct.load_library('myfunc.dll', os.path.dirname(os.path.abspath(__file__)))文件C:Usersgifr9302AppDataLocalProgramsPythonPython37libsite-packages
umpyctypeslib.py",第 152 行,在 load_library返回 ctypes.cdll[libpath]文件C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes\__init__.py",第 431 行,在 __getitem__返回 getattr(self, name)文件C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes\__init__.py",第 426 行,在 __getattr__ 中dll = self._dlltype(name)文件C:Usersgifr9302AppDataLocalProgramsPythonPython37libctypes\__init__.py",第 356 行,在 __init__ 中self._handle = _dlopen(self._name, mode)OSError: [WinError 193] %1 n'est pas une application Win32 valide

翻译:

OSError: [WinError 193] %1 不是有效的 Win32 应用程序

我尝试创建一个 dll 而不是 so 文件,但仍然遇到相同的错误.它似乎试图在 64 位系统上运行 32 位应用程序,但我不知道为什么.有人可以帮忙吗?

解决方案

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

根本错误是ERROR_BAD_EXE_FORMAT(1930xC1).在 [MS.文档]:系统错误代码 (0-499).这是一个一般Win错误(与Python无关).在当前情况下(与 Python 相关),异常是一个 (Python) 包装器.

1.错误

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

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

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

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

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

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

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

main00.c:

#include #include int main(){DWORD gle = 0;HMODULE hMod = LoadLibraryA(.\dll00.dll");如果(hMod == NULL){gle = GetLastError();printf("LoadLibrary failed: %d (0x%08X)
", gle, gle);} 别的 {自由图书馆(hMod);}返回 gle;}

输出:

  • 注意:我会重复使用这个cmd控制台,即使复制/粘贴片段会分散在答案中

[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057187566]>蝙蝠### 设置更短的提示以更好地适合粘贴到 StackOverflow(或其他)页面中###[提示]>:: 为 064 位构建[提示]>c:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.bat"x64 >空[提示]>目录/b代码00.pydll00_v0.cmain00.c[提示]>cl/nologo main00.c/link/NOLOGO/OUT:main00_064.exemain00.c[提示]>:: 创建无效的 .dll[提示]>回声垃圾>dll00.dll[提示]>目录/b代码00.pydll00.dlldll00_v0.cmain00.cmain00.objmain00_064.exe[提示]>main00_064.exeLoadLibrary 失败:193 (0x000000C1)

正如所见,我创建了一个包含文本垃圾"的文件 dll00.dll,所以它是一个 .dll 文件无效内容.

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

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

在以上两种情况中的任何一种情况下,即使 .dll 包含一个有效的图像(对于不同的架构),从当前进程 PoV 来看它仍然是无效的.为了OK涉及的2个CPU架构必须匹配 .

2.Python 上下文

CTypes 在加载 .dll 时做同样的事情:它调用 [MS.Docs]:.dll 名称上的 LoadLibraryW 函数.
因此,这与 CTypes 尝试加载 .dllPython 进程完全相同.

code00.py:

#!/usr/bin/env python3导入系统导入操作系统将 ctypes 导入为 ctDLL_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")打印(正在尝试加载:[{0:s}]".格式(dll_name))dll00 = ct.CDLL(dll_name)func00 = dll00.dll00Func00func00.restype = ct.c_intres = func00()打印({0:s} 返回 {1:d}".format(func00.__name__, res))如果 __name__ == __main__":打印(Python {0:s} {1:03d}bit on {2:s}
".format(.join(item.strip() for item in sys.version.split(";
")),64 如果 sys.maxsize >0x100000000 否则 32, sys.platform))rc = main(*sys.argv[1:])打印(
完成.")sys.exit(rc)

输出:

[提示]>:: dll00.dll 仍然包含垃圾[提示]>[提示]>[提示]>e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.exe"代码00.pyPython 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 位 (AMD64)] 064 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00.dll]回溯(最近一次调用最后一次):文件code00.py",第 25 行,在 <module> 中.rc = main(*sys.argv[1:])文件code00.py",第 14 行,在主目录中dll00 = ct.CDLL(dll_name)文件c:Installpc064PythonPython3.07.09libctypes\__init__.py",第 364 行,在 __init__ 中self._handle = _dlopen(self._name, mode)OSError: [WinError 193] %1 不是有效的 Win32 应用程序

这是 (#1) 的示例,它尝试了所有 4 种组合.

dll00_v0.c:

#include #如果已定义(_WIN32)# 定义 DLL00_EXPORT_API __declspec(dllexport)#别的# 定义 DLL00_EXPORT_API#万一DLL00_EXPORT_API size_t dll00Func00(){返回大小(空*);}

输出:

[提示]>:: 仍在从之前的 vcvarsall 调用中构建 064 位[提示]>[提示]>cl/nologo/DDLL dll00_v0.c/link/NOLOGO/DLL/OUT:dll00_064.dlldll00_v0.c创建库 dll00_064.lib 和对象 dll00_064.exp[提示]>[提示]>:: 为 032 位构建[提示]>c:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.bat"x86**************************************************************************** Visual Studio 2017 开发人员命令提示符 v15.9.40** 版权所有 (c) 2017 Microsoft Corporation**************************************************************************[vcvarsall.bat] 环境初始化为:'x86'[提示]>cl/nologo/DDLL dll00_v0.c/link/NOLOGO/DLL/OUT:dll00_032.dlldll00_v0.c创建库 dll00_032.lib 和对象 dll00_032.exp[提示]>目录/b *.dlldll00.dlldll00_032.dlldll00_064.dll[提示]>[提示]>:: Python 064位[提示]>[提示]>e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.exe"code00.py dll00_064Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 位 (AMD64)] 064 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_064.dll]dll00Func00 返回 8完毕.[提示]>[提示]>e:WorkDevVEnvspy_pc064_03.07.09_test0Scriptspython.exe"code00.py dll00_032Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:58:18) [MSC v.1900 64 位 (AMD64)] 064 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_032.dll]回溯(最近一次调用最后一次):文件code00.py",第 25 行,在 <module> 中.rc = main(*sys.argv[1:])文件code00.py",第 14 行,在主目录中dll00 = ct.CDLL(dll_name)文件c:Installpc064PythonPython3.07.09libctypes\__init__.py",第 364 行,在 __init__ 中self._handle = _dlopen(self._name, mode)OSError: [WinError 193] %1 不是有效的 Win32 应用程序[提示]>[提示]>:: Python 032位[提示]>[提示]>e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.exe"code00.py dll00_032Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 位(英特尔)] 032 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_032.dll]dll00Func00 返回 4完毕.[提示]>[提示]>e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.exe"code00.py dll00_064Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 位(英特尔)] 032 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_064.dll]回溯(最近一次调用最后一次):文件code00.py",第 25 行,在 <module> 中.rc = main(*sys.argv[1:])文件code00.py",第 14 行,在主目录中dll00 = ct.CDLL(dll_name)文件c:Installpc032PythonPython3.07.09libctypes\__init__.py",第 364 行,在 __init__ 中self._handle = _dlopen(self._name, mode)OSError: [WinError 193] %1 不是有效的 Win32 应用程序

3.奖金

在上面的示例中,.dll 是按需"加载的.通过显式调用LoadLibrary(或LoadLibraryEx).
另一种情况是 .exe.dll 依赖(链接)另一个 .dll,并自动加载它当自身被加载时(尽管我几乎可以肯定 LoadLibrary - 或者可能是一个较低级别的函数 - 在依赖 .dll 的引擎盖下被自动调用).
在下面的例子中,dll00*.dll依赖于dll01*.dll.
仅以032bit为例(因为这是之前操作设置的当前构建环境).

dll01.h:

#if defined(_WIN32)# 如果定义(DLL01_EXPORTS)# 定义 DLL01_EXPORT_API __declspec(dllexport)#  别的# 定义 DLL01_EXPORT_API __declspec(dllimport)#  万一#别的# 定义 DLL01_EXPORT_API#万一DLL01_EXPORT_API 无效 dll01Func00();

dll01.c:

#include #define DLL01_EXPORTS#include "dll01.h";无效 dll01Func00(){printf("在 [%s]
", __FUNCTION__);}

dll00_v1.c:(修改后的dll00_v0.c):

#include #如果已定义(_WIN32)# 定义 DLL00_EXPORT_API __declspec(dllexport)#别的# 定义 DLL00_EXPORT_API#万一#include "dll01.h";DLL00_EXPORT_API size_t dll00Func00(){dll01Func00();返回大小(空*);}

输出:

[提示]>:: 仍在为之前的 vcvarsall 调用构建 032 位[提示]>[提示]>cl/nologo/DDLL dll01.c/link/NOLOGO/DLL/OUT:dll01_032.dlldll01.c创建库 dll01_032.lib 和对象 dll01_032.exp[提示]>cl/nologo/DDLL dll00_v1.c/link/NOLOGO/DLL/OUT:dll00_032.dlldll00_v1.c创建库 dll00_032.lib 和对象 dll00_032.expdll00_v1.obj:错误 LNK2019:未解析的外部符号 __imp__dll01Func00 在函数 _dll00Func00 中引用dll00_032.dll:致命错误 LNK1120:1 个未解析的外部[提示]>[提示]>cl/nologo/DDLL dll00_v1.c/link/NOLOGO/DLL/OUT:dll00_032.dll dll01_032.libdll00_v1.c创建库 dll00_032.lib 和对象 dll00_032.exp[提示]>[提示]>e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.exe"code00.py dll00_032Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 位(英特尔)] 032 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_032.dll]在 [dll01Func00]dll00Func00 返回 4完毕.[提示]>:: 搞砸 dll01_032.dll[提示]>回声垃圾>dll01_032.dll[提示]>e:WorkDevVEnvspy_pc032_03.07.09_test0Scriptspython.exe"code00.py dll00_032Python 3.7.9 (tags/v3.7.9:13c94747c7, Aug 17 2020, 18:01:55) [MSC v.1900 32 位(英特尔)] 032 位在 win32 上正在尝试加载:[e:WorkDevStackOverflowq057187566dll00_032.dll]回溯(最近一次调用最后一次):文件code00.py",第 25 行,在 <module> 中.rc = main(*sys.argv[1:])文件code00.py",第 14 行,在主目录中dll00 = ct.CDLL(dll_name)文件c:Installpc032PythonPython3.07.09libctypes\__init__.py",第 364 行,在 __init__ 中self._handle = _dlopen(self._name, mode)OSError: [WinError 193] %1 不是有效的 Win32 应用程序

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

4.结论

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

  • 在上面的示例中,错误发生在正在加载的 .dll 或其直接依赖项之一(间接级别 1)中.不难发现多次应用相同的原则,行为不会改变,因此它对任何级别的间接都是有效的.
    想象一个 .dll 依赖于其他几个 .dll ,而其中的每一个又依赖于其他几个,依此类推.......这称为依赖树.因此,无论在树中的哪个位置发生此错误,它都会向上传播到根节点(即 .dll)
  • 依赖树传播也适用于其他错误.另一个广泛遇到的ERROR_MOD_NOT_FOUND(1260x7E).这意味着没有找到具有指定名称的 .dll(重述:或它(递归)依赖的任何其他 .dll).
    作为旁注,要检查 .dll(或 .exe)依赖项,请使用 Dependency Walker(较新的[GitHub]:lucasg/Dependenciesa>) 或 dumpbin(VStudio 安装的一部分),或者事实上,任何能够获取 PE 依赖信息的工具
  • 讨论的所有内容也适用:
    • 如果 .dll 是正在导入的扩展模块 (.pyd)
    • 如果 .dll 由于导入另一个模块而被加载
  • 讨论的所有内容也适用于 Nix 系统,错误(和相应的消息)明显不同

I have tried to run an exemple of a python code that gets a function from a library using ctypes. The exemple can be found here. I followed the instruction and beside one minor modification, I have used the exact same code. I have been trying to run this on Windows 10 (64-bit), python 3.7 (64-bit) but got this error message:

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

translated:

OSError: [WinError 193] %1 is not a valid Win32 application

I have tried to create a dll instead of a so file and still got the same error. It would seem it tries to run a 32-bit application on a 64-bit system but I'm not sure why. Can anyone help?

解决方案

Mentioning [Python.Docs]: ctypes - A foreign function library for Python (although this doesn't have very much to do with it) just in case.

The underlying error is ERROR_BAD_EXE_FORMAT (193, 0xC1). Check it in [MS.Docs]: System Error Codes (0-499). It's a general Win error (not related to Python). In the current case (related to Python), the exception is a (Python) wrapper over it.

1. The error

The error message is confusing (especially because of %1 placeholder). For more details on that, check [SO]: Why is %1 rarely substituted in "%1 is not a valid Win32 application.".

This error occurs when Win tries to load what it thinks it's an executable (PE) image (.exe, .dll, ...), but it actually isn't. There's a variety of situations when this is encountered (Googleing the error, would yield lots of results).

There are a bunch of possible reasons for this to happen when the image is loaded from a file (existing and readable, otherwise the error would differ - look at one of the bullets at the answer end):

  • Was downloaded and the download is incomplete
  • Was (mistakenly) overwritten (or messed up with)
  • Is corrupt because of filesystem problem
  • Many many more

2 main usecases lead to this error:

  1. Attempting to run a file which is not an .exe ([SO]: OSError: [WinError 193] %1 is not a valid Win32 application)
  2. Trying to load a .dll in a process (running .exe). This is the one that I'm going to focus on

Below, it's an example of a dummy executable attempting to load a .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)
", gle, gle);
    } else {
        FreeLibrary(hMod);
    }
    return gle;
}

Output:

  • Note: I'll be reusing this cmd console, even if the copy / paste snippets will be scattered across the answer

As seen, I created a file dll00.dll containing the text "garbage", so it's a .dll file with invalid contents.

The most common case for this error, is an architecture mismatch:

  • 064bit process attempting to load a 032bit .dll
  • 032bit process attempting to load a 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 .

2. Python context

CTypes does the same thing when loading a .dll: it calls [MS.Docs]: LoadLibraryW function on the .dll name.
So this is the exact same case for the Python process where CTypes tries to load the .dll in.

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

Output:

Here's an example for (#1) , 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:

3. Bonus

In the above examples, the .dll was loaded "on demand" by explicitly calling LoadLibrary (or LoadLibraryEx).
The other case is when a .exe or .dll depends on (was linked against) another .dll, and loads it automatically when itself is being loaded (although I'm almost certain that LoadLibrary - or maybe a lower level function - is automatically called under the hood on the dependent .dll).
In the example below, dll00*.dll depends on dll01*.dll.
Only exemplifying for 032bit (as this is the current build environment set by previous operation).

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: (modified 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:

Stating the obvious: Same error would occur if instead of writing garbage data into dll01_032.dll, I would have build it for 064bit, but I chose this variant as it's shorter.

4. Conclusions

Everything that I'll state in each of the next bullets, also applies to the ones that follow it.

  • In the examples above, the error occurred when the corruption was in the very .dll being loaded, or in one of its direct dependents (level 1 of indirection). It's not hard to figure out that applying the same principle multiple times, the behavior wouldn't change, so it's valid for any level of indirection.
    Imagine a .dll that depends on several other .dlls, and each of those depends in turn on several others, and so on ... . That is called a dependency tree. So no matter where in the tree this error will occur, it will be propagated up to the root node (which is the .dll)
  • The dependency tree propagation applies to other errors as well. Another one that it's widely encountered is ERROR_MOD_NOT_FOUND (126, 0x7E). It means that the .dll with the specified name (restating: or any other .dll that it (recursively) depends on) was not found.
    As a side note, in order to check a .dll (or .exe) dependencies, use Dependency Walker (newer [GitHub]: lucasg/Dependencies) or dumpbin (part of VStudio installation), or as a matter of fact, any tool that is capable of getting PE dependency information
  • Everything discussed also applies:
    • If the .dll is an extension module (.pyd) that is being imported
    • If the .dll is being loaded as a result of another module being imported
  • Everything discussed also applies to Nix systems, the errors (and corresponding messages), obviously differ

这篇关于Python Ctypes - 加载 dll 引发 OSError: [WinError 193] %1 不是有效的 Win32 应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 05:59