c - Python Ctypes - 加载 dll 抛出 OSError: [WinError 193] %1 不是有



我尝试运行一个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:Usersgifr9302AppDataLocalProgramsPythonPython37libsite-packagesnumpyctypeslib.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 文件,但仍然收到相同的错误。似乎它尝试在 32 位系统上运行 64 位应用程序,但我不确定为什么。谁能帮忙?

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

潜在的错误是ERROR_BAD_EXE_FORMAT(193,0xC1)。在 [MS.文档]:系统错误代码 (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]:如何构建libjpeg 9b的DLL版本?(@CristiFati的回答)有关在 Win上构建命令行的详细信息)。

主00.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:WorkDevStackOverflowq057187566]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[prompt]> :: Build for 064bit (pc064)
[prompt]> "c:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.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

  • 尝试加载064.dll032 位进程

在上述 2 种情况下,即使.dll包含有效映像(对于不同的体系结构),它仍然对当前进程PoV无效。要使事情正常运行所涉及的 2个 CPU体系结构必须匹配(1)。

2.蟒蛇上下文

CTypes在加载.dll时执行相同的操作:它调用 [MS.Docs]:.dll名称上的 LoadLibraryW 函数。
因此,对于Python进程来说,CTypes尝试加载.dll的情况完全相同。

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}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)

注意:检查 [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:Installpc064PythonPython3.07.09libctypes__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 is not a valid Win32 application

这是 的示例(从上面开始),它尝试了所有 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:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.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:Installpc064PythonPython3.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:Installpc032PythonPython3.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]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 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:Installpc032PythonPython3.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,而是为064 位构建它,则会发生同样的错误,但我选择了这个变体,因为它更短。

4. 结论

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

  • 在上面的示例中,当损坏位于正在加载的.dll或其直接依赖项之一(间接级别 1)中时,会发生错误。不难发现,多次应用相同的原则,行为不会改变,因此它对任何级别的间接关系都有效。
    想象一下,一个.dll依赖于其他几个.dll,每个又依赖于其他几个,依此类推......这称为依赖树。因此,无论此错误发生在树中的哪个位置,它都会传播到根节点(即.dll)

  • 依赖树传播也适用于其他错误。另一个广泛遇到的ERROR_MOD_NOT_FOUND(126,0x7E)。这意味着找不到具有指定名称(restating:或它(递归)依赖的任何其他.dll)的.dll。检查 [SO]:无法在 Python 中导入 dll 模块(@CristiFati的答案)以获取有关该主题的更多详细信息(也在Python上下文中)。
    作为旁注,为了检查.dll(或.exe)依赖项,请检查 [SO]:使用命令行发现缺少的模块("DLL 加载失败"错误)(@CristiFati的答案),或者事实上,使用任何能够获取PE依赖项信息的工具

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

    • 导入扩展模块(.pyd (.soonNix))时。没错,.pyd只是一个.dll(它导出了一个PyInit_*函数)。查看 [Python.Docs]:使用 C 或 C++ 扩展 Python 以获取更多详细信息

    • 如果由于导入了另一个模块(.pyd.py、...)而加载了.dll

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

5.总结

确保:

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

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

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

一些现实生活中的场景步骤导致这里:

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

  2. 为该软件(在本例中为(扩展)模块)安装(创建、构建)某种插件(包含.dlls)

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

正如@CristiFati所说,发生这种情况是因为

1)64位进程尝试加载32位.dll

2)32位进程尝试加载64位.dll

溶液:

--> 我也遇到了同样的问题,并注意到我的 gcc 编译器正在生成 32 位编译文件而不是 64 位。所以我更改了生成 64 位文件的编译器。

--.exe>您可以通过 -->右键单击 --> 属性 --> 兼容性 -->选中兼容模式选项-->选择下拉列表 如果您在列表中看到 Windows XP,则您的编译器正在生成 32 位文件 如果您没有看到 Windows XP,则您的编译器正在生成 64 位文件。

只是为了增加一点保证它的价值,我也遇到了同样的问题,但认为我在 Win32 上安装了 64 位版本的所有内容,如果这是真的,答案将不适用于我的情况。然而,在检查时,我发现我在等式的C端使用了mingw32位,在Python端使用了64位。我安装了 Python 版本 32.10.6,瞧,一切正常。所以,对于第二个Manoj D Bhat,@CristiFati的最后一句话在我的情况下是正确的 - 通常的错误原因是:

1)64位进程尝试加载32位.dll

2)32位进程尝试加载64位.dll

感谢您的详细解释。

但对于那些想要直接解决方案的人来说。 我认为您应该设置 64 位 python 版本,问题将得到解决。它对我有用。

最新更新