1. 加载 Windows API 和 C 运行库

先看例子

from ctypes import *
u32 = windll.LoadLibrary('user32.dll') #加载user32.dll
u32.MessageBoxW(0, u'内容', u'标题',0)
crt = cdll.LoadLibrary('msvcrt.dll') #加载C运行库
crt.printf('hello world !\n')

调用 C 库用 cdll,而调用 Windows API 用 windll。

之所以有 cdll 和 windll 的区别,是因为 Windows API 和 C 库函数的调用规范不一样,前者遵从的是 __stdcall,后者是 __cdecl。

__cdecl 是 C Declaration 的缩写,表示 C 编译器默认的函数调用规范,这种方式下由调用者负责清理参数栈。比如在VC中,如果函数前面不加任何修饰,默认的就是 __cdecl。

__stdcall 是 Standard Call 的缩写,这种方式下被调的函数自己负责清理参数栈。在 VC 中,如果函数前有 __stdcall 修饰的话,编译出来的就是这种类型。

Windows API 全部采用的是 __stdcall 。因为 Windows API 要被各种编译器下的各种语言调用,如果采用 __cdecl 的方式,由于各种编译器中使用的栈结构也许并不相同,所以就不敢保证其每种编译器都能正确清理 Windows API 产生的参数栈。而采用 __stdcall 的方式,由被调用者自己清理参数栈,就能避免了以上麻烦。

在 Windows 环境,LoadLibrary() 的参数可以不包括扩展名。还有一种更简短的写法,比如下面三个是等效的:

from ctypes import *
windll.LoadLibrary('user32.dll').MessageBoxW(0, u'内容', u'标题',0)
windll.LoadLibrary('user32').MessageBoxW(0, u'内容', u'标题',0)
windll.user32.MessageBoxW(0, u'内容', u'标题',0)

下面三个也一样

from ctypes import *
cdll.LoadLibrary('msvcrt.dll').printf('hello world !\n')
cdll.LoadLibrary('msvcrt').printf('hello world !\n')
cdll.msvcrt.printf('hello world !\n')

2. 隐式类型转换

int、str、unicode,这三种类型是可以直接作为参数传递的,不用指明对应的C类型

from ctypes import *
cdll.msvcrt.printf('%d, %s\n', 100, 'abc')

3. 显式类型转换

int、str、unicode 之外的类型在作为参数时要做显式类型转换,指出对应的C类型

from ctypes import *
cdll.msvcrt.printf('%.2f\n', c_double(3.14))

4. 指针和引用

byref() 可以引用内存地址,相当于 C 的 &

from ctypes import *
i = c_int(0)
cdll.msvcrt.sscanf('100', '%d', byref(i))
print i.value

pointer() 也可以达到相同的效果

from ctypes import *
i = c_int(0)
cdll.msvcrt.sscanf('100', '%d', pointer(i))
print i.value

二者的区别在于,pointer() 会构造一个指针对象,而 byref() 只是一个函数,所以 byref() 的开销较小。

如果只是用于传递参数,那么用 byref() 就足够了。

5. 字符串指针

直接用 create_string_buffer() 和 create_unicode_buffer()

from ctypes import *
s = create_string_buffer('abc') #初始值abc
cdll.msvcrt.sscanf('def', '%s', s)
print s.value #现在是def

6. 回调函数

为了测试回调函数,先编写一个 test.dll,下面是 C 代码

 #include <stdio.h>
typedef void __stdcall (*MyCallback)(int);
__declspec(dllexport) void __stdcall TestMyCallback( int i, MyCallback mycallback)
{
printf("TestMyCallback:%d\n", i);
mycallback(i*10);
}

上面这个函数接受两个参数,第一个是整型变量 i,第二个是一个回调函数。

首先打印变量 i,然后再把 i*10 传给回调函数。

( __declspec(dllexport) 关键字用于从dll导出函数,详见这里 )

下面的Python代码中实现了回调函数,并传给了test.TestMyCallbackPython

from ctypes import *
def mycallback( i ):
print 'mycallback:', i
c_mycallback = WINFUNCTYPE(None, #返回值类型 None 代表 void
c_int #第一个参数类型 int
)(mycallback) #括号内是需要被包装的Python函数
windll.test.TestMyCallback(100, c_mycallback)

WINFUNCTYPE 的用法实际包括两个步骤:

  • 首先要声明一个 C 函数原型
c_function_type = WINFUNCTYPE(返回值类型,第一个参数类型,第二个参数类型...)
  • 然后再用这个原型包装 Python 函数
c_function = c_function_type(Python函数)

WINFUNCTYPE 遵守 __stdcall 调用规范,对应的 __cdecl 版本是 CFUNCTYPE

ctypes 调用 dll的更多相关文章

  1. ctypes库调用dll的个人见解

    最近着手开发一个小东西涉及到了API接口的知识点, 第一次使用到了ctypes库,在网上找了一大圈,基本都是讲add.dll之后就没了. 就像下面这个: from ctypes import * dl ...

  2. Python调用DLL动态链接库——ctypes使用

    最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用. ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调 ...

  3. python调用dll方法

    在python中调用dll文件中的接口比较简单,实例代码如下: 如我们有一个test.dll文件,内部定义如下: extern "C"{ int __stdcall test( v ...

  4. Python手机开发调用DLL实现部分ADB功能-乾颐堂

    近期学了一点Python,然后正好有一个手机同步工具方面的预研工作要完成. 要实现PC与手机的通信,首先要找到他们的通信协议,还好的是Android有完善的协议:ADB ADB的代码是开源的,而且支持 ...

  5. python调用dll详解

    参考链接https://www.cnblogs.com/TQCAI/p/8881530.html https://www.jb51.net/article/52513.htm https://www. ...

  6. Windows平台Go调用DLL的坑

    最近的项目中,使用了GO来开发一些服务中转程序.业务比较简单,但是有一些业务需要复用原有C++开发的代码.而在WINDOWS,用CGO方式来集成C/C++代码并不是太方便.所以用DLL把C++的代码封 ...

  7. Java 调用 C++ (Java 调用 dll)康哥手把手教你

    摘要: 本文原创,转载请注明地址 http://www.cnblogs.com/baokang/p/4979243.html 因为要做点图形处理的项目,需要在Java中调用dll库,所以开发的第一步是 ...

  8. 【转】C#调用DLL

    C#中如何调用动态链接库DLL(转)     每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基 ...

  9. C#程序实现动态调用DLL的研究(转)

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

随机推荐

  1. IT人士怎样的休息方式才高效

    为什么你睡了11个小时仍然觉得疲累? 为什么你花了好几万去岛国度假并没有增加生活的热情? 都说要去KTV,去夜店,去游乐园就能忘掉不快,更带劲地开始新的一天,但是尽兴归来心里只剩空虚? 我们真的明白休 ...

  2. mysql 基础 增删改查语句

    MySQL:众多关系型数据库中的一种仓库 --数据库箱子 --表数据库:进入mysql 命令行: mysql -uroot -p查看所有数据库: show databases;创建数据库: creat ...

  3. <转>MySQL性能调优的10个方法

    文章原地址:http://mp.weixin.qq.com/s/oRXJRz_Y5drmIrcbxSKOcw 1. 选择合适的存储引擎: InnoDB 除非你的数据表使用来做只读或者全文检索 (相信现 ...

  4. BZOJ 3944 Sum

    题目链接:Sum 嗯--不要在意--我发这篇博客只是为了保存一下杜教筛的板子的-- 你说你不会杜教筛?有一篇博客写的很好,看完应该就会了-- 这道题就是杜教筛板子题,也没什么好讲的-- 下面贴代码(不 ...

  5. Android开发之import org.apache.http

    在build.gradle(app)中添加一下依赖: android { useLibrary 'org.apache.http.legacy' } dependencies { compile 'o ...

  6. haproxy利用ACL规则封禁自定义IP地址拒绝访问

    现在有一个需求就是在发版的时候希望除公司IP外的外网访问服务的时候都是拒绝访问的 现在利用haproxy 的acl规则作出限制 errorfile       403 /etc/haproxy/err ...

  7. Android 和 H5 通信

    有需要与h5通信的需求,写了一个helper类,处理与h5通信. import android.content.Context; import android.os.Handler; import a ...

  8. oracle Entity db.Database.SqlQuery ORA-01843: 无效的月份

    原因是oracle的日期格式化格式和本地语言环境的日期格式不一致导致的. 一般情景为oralce格式为英文格式 本地服务器或者开发机的环境为中文环境. 使用Dbcontext 实例一般不会有问题. 但 ...

  9. Leetcode 16. 3Sum Closest

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  10. HiShop2.x版本中的上传插件分析,得出所用的模板语言为Underscore.js 1.6.0且自己已修改

    效果: 上传组件非常的酷,但是分析其使用JS写法使用了模板语言的,代码如下: <script type="text/j-template" id="tpl_popb ...