Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
543 views
in Technique[技术] by (71.8m points)

c - Python Ctypes - loading dll throws OSError: [WinError 193] %1 is not a valid Win32 application

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?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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
  • Is corrupt because of filesystem problem
  • Was mistakenly overwritten
  • 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.

code0.c:

#include <stdio.h>
#include <Windows.h>


int main() {
    DWORD gle = 0;
    HMODULE hMod = LoadLibraryA(".\dll0.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 a side note, I don't know why this snippet is messed up (as opposed to others), the best (not perfect) workaround I found is to split it in 3
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq057187566]> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> "c:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.bat" x64
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.22
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
[prompt]> dir /b
code0.c
dll0.c
script0.py

[prompt]> cl /nologo code0.c  /link /NOLOGO /OUT:code0_064.exe
code0.c

[prompt]> :: Creating an invalid dll
[prompt]> echo garbage> dll0.dll

[prompt]> dir /b
code0.c
code0.obj
code0_064.exe
dll0.c
dll0.dll
script0.py

[prompt]> code0_064.exe
LoadLibrary failed: 193 (0x000000C1)

As seen, I created a file dll0.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:

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

script0.py:

#!/usr/bin/env python3

import sys
import os
import ctypes


DLL_BASE_NAME = "dll0"


def main(args):
    dll_name = os.path.join(os.path.abspath(os.path.dirname(__file__)), (args[0] if args else DLL_BASE_NAME) + ".dll")
    print("Attempting to load: [{0:s}]".format(dll_name))
    dll0 = ctypes.CDLL(dll_name)
    func0 = dll0.dll0Func0
    func0.restype = ctypes.c_int

    res = func0()
    print("{0:s} returned {1:d}".format(func0.__name__, res))


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}
".format(" ".join(item.strip() for item in sys.version.split("
")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(sys.argv[1:])
    print("
Done.")

Output:

[prompt]> :: dll0.dll still contains garbage
[prompt]>
[prompt]> "e:WorkDevVEnvspy_pc064_03.07.03_test0Scriptspython.exe" script0.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Attempting to load: [e:WorkDevStackOverflowq057187566dll0.dll]
Traceback (most recent call last):
  File "script0.py", line 24, in <module>
    main(sys.argv[1:])
  File "script0.py", line 14, in main
    dll0 = ctypes.CDLL(dll_name)
  File "c:installpc064pythonpython3.07.03Libctypes\__init__.py", line 356, 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.

dll0.c:

#include <inttypes.h>

#if defined(_WIN32)
#  define DLL0_EXPORT_API __declspec(dllexport)
#else
#  define DLL0_EXPORT_API
#endif


DLL0_EXPORT_API size_t dll0Func0() {
    return sizeof(void*);
}

Output:

[prompt]> :: Still building for 64bit from previous vcvarsall call
[prompt]>
[prompt]> cl /nologo /DDLL dll0.c  /link /NOLOGO /DLL /OUT:dll0_064.dll
dll0.c
   Creating library dll0_064.lib and object dll0_064.exp

[prompt]>
[prompt]> "c:Installpc032MicrosoftVisualStudioCommunity2017VCAuxiliaryBuildvcvarsall.bat" x86
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.22
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'

[prompt]> cl /nologo /DDLL dll0.c  /link /NOLOGO /DLL /OUT:dll0_032.dll
dll0.c
   Creating library dll0_032.lib and object dll0_032.exp

[prompt]> dir /b *.dll
dll0.dll
dll0_032.dll
dll0_064.dll

[prompt]>
[prompt]> :: Python 64bit
[prompt]> "e:WorkDevVEnvspy_pc064_03.07.03_test0Scriptspython.exe" script0.py dll0_064
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Attempting to load: [e:WorkDevStackOverflowq057187566dll0_064.dll]
dll0Func0 returned 8

Done.

[prompt]> "e:WorkDevVEnvspy_pc064_03.07.03_test0Scriptspython.exe" script0.py dll0_032
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Attempting to load: [e:WorkDevStackOverflowq057187566dll0_032.dll]
Traceback (most recent call last):
  File "script0.py", line 24, in <module>
    main(sys.argv[1:])
  File "script0.py", line 14, in main
    dll0 = ctypes.CDLL(dll_name)
  File "c:installpc064pythonpython3.07.03Libctypes\__init__.py", line 356, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 is not a valid Win32 application

[prompt]>
[prompt]> :: Python 32bit
[prompt]> "e:WorkDevVEnvspy_pc032_03.07.03_test0Scriptspython.exe" script0.py dll0_032
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32

Attempting to load: [e:WorkDevStackOverflowq057187566dll0_032.dll]
dll0Func0 returned 4

Done.

[prompt]> "e:WorkDevVEnvspy_pc032_03.07.03_test0Scriptspython.exe" script0.py dll0_064
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32

Attempting to load: [e:WorkDevStackOverflowq057187566dll0_064.dll]
Traceback (most recent call last):
  File "script0.py", line 24, in <module>
    main(sys.argv[1:])
  File "script0.py", line 14, in main
    dll0 = ctypes.CDLL(dll_name)
  File "c:installpc032pythonpython3.07.03Libctypes\__init__.py", line 356, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 is not a valid Win32 application

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, dll0*.dll depends on dll1*.dll. Only exemplifying for 32bit (as this is the current build environment set by previous operation).

dll1.h:

#if defined(_WIN32)
#  if defined(DLL1_EXPORTS)
#    define DLL1_EXPORT_API __declspec(dllexport)
#  else
#    define DLL1_EXPORT_API __declspec(dllimport)
#  endif
#else
#  define DLL1_EXPORT_API
#endif


DLL1_EXPORT_API void dll1Func0();

dll1.c:

#include <stdio.h>
#define DLL1_EXPORTS
#include "dll1.h"


void dll1Func0() {
    printf("In [%s]
", __FUNCTION__);
}

dll0.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...