介绍
如何在python中调用c dll接口。c dll接口会用到一些指针的指针,结构体,回调函数等,文章总结了一些常见用法。
.h 代码
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32) /* windows */
#define EXPORT_API __declspec(dllexport)
#else
#define EXPORT_API __declspec(dllimport)
#endif
/* 函数标准调用约定 Standard function calling convention */
#ifdef i386
#ifndef STDCALL
#define STDCALL __attribute__((stdcall))
#endif
#else
#ifndef WIN32
#ifndef STDCALL
#define STDCALL
#endif
#else
#ifndef STDCALL
#define STDCALL __stdcall
#endif
#endif
#endif
/*
* 说明: 版本为x64版本,基于vs2019,使用前需要先安装依赖库 VC_redist15-17-19-22.x64.exe
* 中文编码格式为utf8
*/
#define IN
#define OUT
#define INOUT
struct ST_IMAGE
{
int int_type;
float float_type;
double double_type;
long long int64_type;
char char_type;
unsigned char* ptr_type;
};
typedef void (STDCALL *image_CallBack_PF)(ST_IMAGE stImage,void* pUser);
EXPORT_API void STDCALL interface_func_void();
EXPORT_API int STDCALL interface_func_int(int a);
EXPORT_API char* STDCALL interface_func_more_point(int a,IN char *pstr,IN ST_IMAGE image,INOUT ST_IMAGE *pimage);
EXPORT_API int STDCALL interface_func_pfunc_pvoid(void* handle,image_CallBack_PF pFunc,void *pUser);
EXPORT_API ST_IMAGE* STDCALL interface_func_more_ppoint(void **handle,IN ST_IMAGE *image);
#ifdef __cplusplus
}
#endif /* end of __cplusplus */
参考代码
# -*- coding: utf-8 -*-
#
# python 调用 dll 库的一些方法
#
from ctypes import *
import os
# 加载dll库所在路径到环境变量中
_lib_path = r'./'
os.environ['path'] = f'{_lib_path};' + os.environ['path']
_lib_interface = WinDLL(os.path.join(_lib_path,'py_load_dll.dll'))
winfun_ctype = WINFUNCTYPE
class _interface_image_(Structure):
pass
ImageCallBackDef = winfun_ctype(None, _interface_image_, c_void_p)
_interface_image_._fields_ = [
('int_type',c_int32),
('float_type',c_float),
('double',c_double),
('int64_type',c_int64),
('char_type',c_char),
('ptr_type',POINTER(c_ubyte))
]
class dll_interface:
def __init__(self):
self._handle = _interface_image_()
self.handle = pointer(self._handle)
@staticmethod
def interface_func_void():
# void STDCALL interface_func_void();
_lib_interface.interface_func_void()
@staticmethod
def interface_func_int(a:int)->int:
_lib_interface.interface_func_int.restype = c_int32
_lib_interface.interface_func_int.argtypes = (c_int32,)
# int STDCALL interface_func_int(int a);
return _lib_interface.interface_func_int(a)
@staticmethod
def interface_func_more_point(a:int,b:c_int32,msg:str,stImage,outImage)->str:
p_b = byref(b)
b_msg = msg.encode('gbk')
p_image = byref(outImage)
_lib_interface.interface_func_more_point.restype = c_char_p
_lib_interface.interface_func_more_point.argtypes = (c_int32,c_void_p,c_void_p,_interface_image_,c_void_p)
# char* STDCALL interface_func_more_point(int a,IN char *pstr,IN ST_IMAGE image,INOUT ST_IMAGE *pimage);
return bytes.decode(_lib_interface.interface_func_more_point(a,p_b,b_msg,stImage,p_image))
def interface_func_pfunc_pvoid(self,call_back_func,pUser)->int:
_lib_interface.interface_func_pfunc_pvoid.restype = c_int32
_lib_interface.interface_func_pfunc_pvoid.argtypes = (c_void_p,c_void_p,c_void_p)
# int STDCALL interface_func_pfunc_pvoid(void* handle,image_CallBack_PF pFunc,void *pUser);
# typedef void (STDCALL *image_CallBack_PF)(ST_IMAGE stImage,void* pUser);
return _lib_interface.interface_func_pfunc_pvoid(self.handle,call_back_func,pUser)
def interface_func_more_ppoint(self,image:_interface_image_)->pointer:
_lib_interface.interface_func_more_ppoint.restype = c_void_p
_lib_interface.interface_func_more_ppoint.argtypes = (c_void_p,c_void_p)
# ST_IMAGE* STDCALL interface_func_more_ppoint(void **handle,IN ST_IMAGE *image);
return _lib_interface.interface_func_more_ppoint(byref(self.handle),byref(image))
def image_callback(st_image,pUser):
print("recv frame:",st_image.int_type,st_image.float_type,st_image.double,st_image.int64_type,pUser)
IMAGE_CALL_BACK_FUNC = ImageCallBackDef(image_callback)
if __name__ == "__main__":
#
dll_interface.interface_func_void()
#
print(dll_interface.interface_func_int(100))
#
inImage = _interface_image_()
inImage.int_type = 1
inImage.float_type = 1.1
inOutImage = _interface_image_()
inOutImage.int_type = 1
inOutImage.float_type = 1.1
b = c_int32(10)
print(dll_interface.interface_func_more_point(1,b,"what",inImage,inOutImage))
print(inOutImage.int_type)
print(b.value) # c_int32 --> int
# interface_func_more_ppoint
obj = dll_interface()
p = obj.interface_func_more_ppoint(inImage)
print(obj._handle.float_type)
# void* 强制类型转换为_interface_image_
stImage = cast(p,POINTER(_interface_image_)).contents
print(stImage.int_type)
# interface_func_more_ppoint
obj.interface_func_pfunc_pvoid(IMAGE_CALL_BACK_FUNC,100)