提及[Python.Docs]: ctypes - A foreign function library for Python(虽然这与它没有太大关系)以防万一。
基础错误是ERROR_BAD_EXE_FORMAT(193,0xC1)。在[MS.Docs]: System Error Codes (0-499) 中查看。这是一个一般Win错误(与Python无关)。在当前情况下(与 Python 相关),例外是对其进行 (Python) 包装器。
1。错误
错误消息令人困惑(尤其是由于 %1 占位符)。更多详情,请查看[SO]: Why is %1 rarely substituted in “%1 is not a valid Win32 application.”。
当 Win 尝试加载它认为是可执行 (PE) 的图像(.exe、)时会发生此错误。 dll, ...),但实际上并非如此。遇到这种情况有多种情况(Google搜索错误,会产生很多结果)。
从文件加载图像时发生这种情况的可能原因有很多(现有且可读,否则错误会有所不同 - 请查看答案末尾的其中一个项目符号 ):
- 已下载,下载不完整
- 被(错误地)覆盖(或弄乱了)
- 由于文件系统问题而损坏
- 还有很多
2 个主要用例导致此错误:
- 试图运行一个不是 .exe 的文件 ([SO]: OSError: [WinError 193] %1 is not a valid Win32 application)
- 试图在进程中加载 .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 控制台,即使复制/粘贴 sn-ps 会分散在答案中
[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)
如所见,我创建了一个包含文本“garbage”的文件 dll00.dll,所以它是一个包含无效内容的 .dll 文件.
此错误最常见的情况是架构不匹配:
- 064bit 进程试图加载 032bit .dll
- 032bit 进程试图加载 064bit .dll
在上述 2 种情况下,即使 .dll 包含有效的图像(对于不同的架构),它在当前进程 PoV 中仍然是无效的。为了让事情运行OK,所涉及的 2 个 CPU 架构必须匹配 (1) .
2。 Python 上下文
CTypes 在加载 .dll 时做同样的事情:它在 .dll 名称上调用 [MS.Docs]: LoadLibraryW function。
所以这与 CTypes 尝试在其中加载 .dll 的 Python 进程完全相同。
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}\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 <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。奖金
在上述示例中,.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 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 又依赖于其他几个,依此类推...。这称为依赖树。所以无论这个错误会在树的哪个位置发生,它都会传播到根节点(即.dll)
- 依赖关系树传播也适用于其他错误。另一个广泛遇到是ERROR_MOD_NOT_FOUND(126,0x7E)。这意味着找不到具有指定名称的 .dll(restating: 或它(递归地)依赖的任何其他 .dll) .
附带说明,为了检查 .dll(或 .exe)依赖关系,请使用Dependency Walker(较新的[GitHub]: lucasg/Dependencies)或 dumpbin(VStudio 安装的一部分),或者事实上,任何能够获取 PE 依赖信息的工具
- 讨论的所有内容也适用:
- 如果 .dll 是正在导入的扩展模块 (.pyd)
- 如果 .dll 由于导入另一个模块而被加载
- 讨论的所有内容也适用于 Nix 系统,错误(和相应的消息)明显不同