V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
gimp
V2EX  ›  Python

请教下 Python 调用 DLL 的问题

  •  
  •   gimp · 2017-06-08 15:06:10 +08:00 · 8480 次点击
    这是一个创建于 2524 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想要调用一个别人给的 dll 文件,总是出错,于是我想着写个最简单的 hello world 版的 dll 文件,调用一下,来确定我在网上找的调用代码是正确的

    这是我看的制作 dll 文件的教程:http://wolfprojects.altervista.org/dllforpyinc.php

    //main.cpp
    #define DLLEXPORT extern "C" __declspec(dllexport)
    
    DLLEXPORT int sum(int a, int b) {
        return a + b;
    }
    
    //main.h
    int sum(int, int);
    
    

    我用 Code::Blocks 自带的 GCC 和 VS2008 分别编译出了 dll 文件,但是调用的时候都会报错

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

    我的环境是 Windows 7(64),Python 3.6.0(64),我也将生成的 dll 放到 XP 上运行过,XP 上是 Python2.7(32)

      File "C:\Python27\lib\ctypes\__init__.py", line 440, in LoadLibrary
        return self._dlltype(name)
      File "C:\Python27\lib\ctypes\__init__.py", line 362, in __init__
        self._handle = _dlopen(self._name, mode)
    WindowsError: [Error 14001]
    

    尝试多次,我按照上边教程中的,在 Linux 下生成 so 库,运行的比较正常

    这是 python 代码,后来我想到下载了一个标准库 msvcrt,可以正常调用

    #!/bin/env python
    # -*- coding: utf-8 -*-
    
    from ctypes import cdll
    
    # mydll = cdll.LoadLibrary('msvcrt.dll')
    # mydll.printf(b"hello world!")
    
    mydll = cdll.LoadLibrary('test.dll')
    print(mydll)
    

    所以我感觉问题还是出在 dll 这方面,这是我的分析:

    1,可能是调用方式问题,查询看 dll 有不同的调用方式有,stdcall cdecl 等,不过我换用 ctypes 的 windll 调用还是不行

    2,可能是编码问题,查询过程中有 ANSI,和 Unicode 两种,看到有人给出如下代码,我用 msvcrt 测试,不过我运行会提示 AttributeError: function 'printf' not found

    libHandle = ctypes.cdll.kernel32.LoadLibraryW('msvcrt.dll')
    lib = ctypes.CDLL(None, handle=libHandle)
    lib.printf(b"hello world!")
    

    现在有点不知从哪里入手解决,先谢谢了

    7 条回复    2017-06-28 18:50:07 +08:00
    Morriaty
        1
    Morriaty  
       2017-06-08 17:46:06 +08:00   ❤️ 1
    没用过这种方式调用 C

    一般是按 PyObject 写 C++,编译之后直接在 python 里面 import
    codingcrush
        2
    codingcrush  
       2017-06-08 18:07:59 +08:00 via Android   ❤️ 1
    可能是平台问题。我自己试过,一个 so 库在 centos 可以工作,在 debian 上不能使用
    weyou
        3
    weyou  
       2017-06-08 18:26:40 +08:00   ❤️ 1
    msvcrt 不用显式 load
    >>> ctypes.cdll.msvcrt.printf(b'hello world!\n')
    hello world!
    13
    weyou
        4
    weyou  
       2017-06-08 18:39:41 +08:00   ❤️ 1
    你用错了调用方式,kernel32 不是 cdll, 是 windll,
    >>> libHandle = ctypes.windll.kernel32.LoadLibraryW('msvcrt.dll')
    >>> lib = ctypes.CDLL(None, handle=libHandle)
    >>> lib.printf(b'hello world!\n')
    hello world!
    13

    至于你自己的 dll,你确定你的 Python 是 64bit 的吗?
    OSError: [WinError 193] %1 不是有效的 Win32 应用程序。
    这句错误可以看出 python 期望你的 dll 是 32bit,所以它自己应该是 32bit 才对。
    am241
        5
    am241  
       2017-06-08 19:22:28 +08:00 via Android   ❤️ 1
    “不是有效的 win32 程序”

    说明 loadlibrary 这一步就错了,大概率是 x86,x64 匹配的原因
    wevsty
        6
    wevsty  
       2017-06-08 19:59:49 +08:00   ❤️ 1
    LoadLibrary 14001 错误
    是因为你的 DLL 没有写 DLLmain,LoadLibrary 在载入 DLL 的时候会自动加载 DLLmain 函数,但是你没有写的话就找不到这个函数,所以加载失败。
    #include <windows.h>
    BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved
    )

    {return true;}
    把这段代码粘进去就好了。
    gimp
        7
    gimp  
    OP
       2017-06-28 18:50:07 +08:00
    感谢各位的回复,这段时间有点忙,今天腾出时间又研究了一下,解决了问题

    记录一下,说不定会有遇到类似问题的朋友通过搜索进来

    主要两个原因

    1,我的 Python 版本是 64 位,dll 是 32 位的,在另一台机器上装上 Python32 位的解决载入的问题(都是 windows7 64 位系统)
    2,调用 dll 的时候我没有进行类型转换,导致函数运行一直没有结果(函数期待 char*,我却传的 python str 类型)

    另外还要注意的是 dll 的类型(__cdecl 还是__stdcall ),还有 dll 的编码方式( ANSI 还是 Unicode ),使用 CDLL 或者 WinDLL 应该可以自动分辨编码

    楼上朋友提到 DLLmain,我没写,生成的 dll 也是可以用的,可能是 code::blocks 创建的工程自动给我添加了

    放两个链接,第一个是我的笔记,第二个链接中介绍了传参及返回值转换

    Python 调用 DLL 文件
    https://blog.yasking.org/a/python-use-dll.html

    python ctypes 探究 ---- python 与 c 的交互
    http://www.cnblogs.com/night-ride-depart/p/4907613.html
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1833 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 86ms · UTC 16:28 · PVG 00:28 · LAX 09:28 · JFK 12:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.