Win7,64位,Python调用C++

20 篇文章 0 订阅

系统: Win7,64位

Python:3.5,64位


1、VS2008下,创建一个DLL。

  头文件:CallC++.h

#ifdef CALLC_EXPORTS
#define CALLC_API __declspec(dllexport)
#else
#define CALLC_API __declspec(dllimport)
#endif


#define ARRAY_NUM	10
#define STR_LEN		30

struct StructInfo
{
	int		iNum;
	int		iArray[ARRAY_NUM];
	char*	pszName;
	char	szName[STR_LEN];
};

#ifdef  __cplusplus
extern  "C"{
#endif

	CALLC_API int Sum(int, int);

	CALLC_API void GetString(char*); 

	CALLC_API char* GetStructInfo(struct StructInfo* pStInfo);

#ifdef  __cplusplus
}
#endif


  源文件:CallC++.cpp

#include "stdafx.h"
#include "CallC++.h"


CALLC_API int Sum(int a, int b)
{
	return a + b;
}

CALLC_API void GetString(char* pszName) 
{ 
	strcpy(pszName, "CallC++ DLL"); 
}

CALLC_API char* GetStructInfo(struct StructInfo* pStInfo)
{
	pStInfo->iNum = 100;
	for (int i = 0; i < ARRAY_NUM; i++)
	{
		pStInfo->iArray[i] = i;
	}
	pStInfo->pszName = "pszName:python call C++!";
	strcpy(pStInfo->szName, "szName:python call C++!");

	return "finish";
}

注意:

(1)弄清楚编译的时候函数的调用约定采用的__cdecl还是__stdcall,因为根据DLL中函数调用约定方式,Python将使用相应的函数加载DLL。

(2)如果采用C++的工程,那么导出的接口需要extern "C",这样Python中才能识别导出的函数。


编译生成的CallC++.dll,复制到Python安装目录下的DLLs目录下,例如C:\Program Files\Python35\DLLs


如果生成的是32位的DLL,使用64位的Python3.5加载时会出错。

Traceback (most recent call last):
  File "C:\Program Files\Python35\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 326, in RunScript
    exec(codeObject, __main__.__dict__)
  File "C:\Users\Administrator\Desktop\CallC++.py", line 3, in <module>
    dll = cdll.LoadLibrary('C:\\Program Files\\Python35\\DLLs\\CallC++.dll')
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 425, in LoadLibrary
    return self._dlltype(name)
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 347, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 不是有效的 Win32 应用程序。

DLL要编译成64位的。

参见 Win7,64位,VS2008的64位编译环境的安装和配置



2、Python中,调用DLL

  dll = cdll.LoadLibrary('CallC++.dll')

  导入动态链接时,如果没有加入完全路径,会出错:

Traceback (most recent call last):
  File "C:\Program Files\Python35\Lib\site-packages\pythonwin\pywin\framework\scriptutils.py", line 326, in RunScript
    exec(codeObject, __main__.__dict__)
  File "C:\Users\Administrator\Desktop\CallC++.py", line 2, in <module>
    dll = cdll.LoadLibrary('CallC++.dll')
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 425, in LoadLibrary
    return self._dlltype(name)
  File "C:\Program Files\Python35\lib\ctypes\__init__.py", line 347, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] 找不到指定的模块。


Python载入 dll 产生的 [WinError 126]的 错误原因

(1) 系统无法定位到你的DLL 动态库

(2)你的DLL 动态库依赖于其他其他DLL 动态库无法被系统找到。


  dll = cdll.LoadLibrary('C:\\Program Files\\Python35\\DLLs\\CallC++.dll')

  导入动态链接时,加入完全路径,就OK了。


  GetStructInfo这个函数通过传递一个StructTest类型的指针,然后对对象中的属性进行赋值,最后返回"finish"。

  Python调用代码如下:

  首先在Python中继承Structure构造一个和DLL中一致的数据结构StructInfo,

  其次设置函数GetStructInfo的参数类型和返回值类型,

  然后创建一个StructInfo对象,并将其转化为指针作为参数,调用函数GetStrcutInfo,

  最后通过输出数据结构的值来检查是否调用成功:

from ctypes import *
#dll = cdll.LoadLibrary('CallC++.dll')
dll = cdll.LoadLibrary('C:\\Program Files\\Python35\\DLLs\\CallC++.dll')
ret = dll.Sum(2, 3)
print (ret)
str = create_string_buffer(15) 
dll.GetString(str)
#print (str.raw)
#print (str.value)
print (str.value.decode())

ARRAY_NUM = 10
STR_LEN = 30

#define type
INTARRAY10 = c_int * ARRAY_NUM;
CHARARRAY30 = c_char * STR_LEN;

#define struct
class StructInfo(Structure):
  _fields_ = [
    ("iNum", c_int),
    ("iArray", INTARRAY10),  
    ("pszName", c_char_p),
    ("szName", CHARARRAY30)
    ]
  
#load dll and get the function object
dll = cdll.LoadLibrary('C:\\Program Files\\Python35\\DLLs\\CallC++.dll');
GetStructInfo = dll.GetStructInfo;

#set the return type
GetStructInfo.restype = c_char_p;

#set the argtypes
GetStructInfo.argtypes = [POINTER(StructInfo)];
objectStruct = StructInfo();

#invoke api GetStructInfo
retStr = GetStructInfo(byref(objectStruct));

#check result
print ("iNum: ", objectStruct.iNum)
print ("pszName: ", objectStruct.pszName.decode())
print ("szName: ", objectStruct.szName.decode())
for i,val in enumerate(objectStruct.iArray):
  print ('Array[i]: ', val)
print (retStr.decode())


3、运行输出结果:

>>> 5
CallC++ DLL
iNum:  100
pszName:  pszName:python call C++!
szName:  szName:python call C++!
Array[i]:  0
Array[i]:  1
Array[i]:  2
Array[i]:  3
Array[i]:  4
Array[i]:  5
Array[i]:  6
Array[i]:  7
Array[i]:  8
Array[i]:  9
finish


小结:
1)使用64位的Python加载32位的DLL,会出错。
2)Python导入动态链接时,如果没有加入完全路径,会出错。
3)Python3.5中,要将bytes转变为str,bytes对象必须要进行解码。使用decode()方法解码



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值