zoukankan      html  css  js  c++  java
  • Python调用C/C++动态链接库

    Python调用C/C++动态链接库

    2013年07月26日 ⁄ 综合 ⁄ 共 3219字 ⁄ 字号    ⁄ 评论关闭
     

    吐槽(可略过):不知不觉,4月份毕业,5月份进入团队,已有7个月。大的方面经历着测试、解决客户问题/bug、出一个产品Patch,小的技术方面经历着C++,Shell,python,linux Kernel以及自动化测试框架,看起来经历都很丰富,但何尝不处于一种浅尝辄止的状态?!似乎就像学生时代,寂寞了,就找点不会的技术学学,然而都钻的不够深入。也许现在的境遇,和自己本身的职位也有所关系,不像Deveploper一样可以专心于某一方向的技术,又不像QA一样钻研自动化测试技术,作为一名SEG,必须要以客户为导向,但又得兼顾着团队内部的事情。也许,会有很多人和我一样,但我们不应该对客观环境妥协,更应该从自身方面进行突破和改变,在不影响工作的情况下,坚持一个自己的爱好和技术点,日积月累,并将所学尽量融合进工作之中,这样的方式也许既不失专业,又能够有很好的进步。

    Python调用C/C++动态链接库的需求

    在自动化测试过程中,难免会遇到语言混合使用的情况,这不,我们也遇到了。初步决定采用Robot Framework作为自动化测试框架后,其支持Java和Python,而Python作为主流的语言,怎么能放弃使用它的机会^_^。
    然而产品采用是古老90年代开发的C/S结构,因为古老,当时也没有考虑到对产品的测试进行自动化,Client端并没有预留CLI(Command Line interface)形式的接口,真是雪上加霜啊。

    那怎么自动化?采用AutoIT来对客户端界面进行自动化测试?可惜AutoIT对当初开发采用的控件识别不是很好,如果采用控件所在位置来进行控制的方式,又会导致自动化测试并不是很稳定。那么!!!只有自己开发接口了,目前在Client端开发出CLI形式的接口,将其封装为DLL,然后在Robot FrameWork框架中采用Python对DLL进行调用。任务艰巨哪!

    Python调用DLL例子

    示例一

    首先,在创建一个DLL工程(本人是在VS 2005中创建),头文件:

    //hello.h
    #ifdef EXPORT_HELLO_DLL
    #define HELLO_API __declspec(dllexport)
    #else
    #define HELLO_API __declspec(dllimport)
    #endif
    
    extern "C"
    {
    	HELLO_API int IntAdd(int , int);
    }
    

    CPP文件:

    //hello.cpp
    #define EXPORT_HELLO_DLL
    #include "hello.h"
    
    HELLO_API int IntAdd(int a, int b)
    {
    	return a + b;
    }

    这里有两个注意点:

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

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

    我的工程中采用__cdecl函数调用约定方式进行编译链接产生hello.dll,然后Python中采用ctypes库对hello.dll进行加载和函数调用:

    from ctypes import *
    dll = cdll.LoadLibrary('hello.dll');
    ret = dll.IntAdd(2, 4);
    print ret;

    OK,一个小例子已经完成了,如果你感兴趣,但还没试过,那就尝试一下吧。

    示例二

    示例一只是一个"hello world"级别的程序,实际运用中更多的需要传递数据结构、字符串等,才能满足我们的需求。那么这个示例将展示,如何传递数据结构参数,以及如何通过数据结构获取返回值。

    首先编写DLL工程中的头文件:

    //hello.h
    #ifdef EXPORT_HELLO_DLL
    #define HELLO_API __declspec(dllexport)
    #else
    #define HELLO_API __declspec(dllimport)
    #endif
    
    #define ARRAY_NUMBER 20
    #define STR_LEN 20
    
    struct StructTest
    {
    	int number;
    	char* pChar;
    	char str[STR_LEN];
    	int iArray[ARRAY_NUMBER];
    };
    
    extern "C"
    {
    	//HELLO_API int IntAdd(int , int);
    	HELLO_API char* GetStructInfo(struct StructTest* pStruct);
    }

    CPP文件如下:

    //hello.cpp
    #include <string.h>
    #define EXPORT_HELLO_DLL
    #include "hello.h"
    
    HELLO_API char* GetStructInfo(struct StructTest* pStruct)
    {
    	for (int i = 0; i < ARRAY_NUMBER; i++)
    		pStruct->iArray[i] = i;
    
    	pStruct->pChar = "hello python!";
    
    	strcpy (pStruct->str, "hello world!");
    
    	pStruct->number = 100;
    
    	return "just OK";
    }

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

    编写Python调用代码如下,首先在Python中继承Structure构造一个和C DLL中一致的数据结构StructTest,然后设置函数GetStructInfo的参数类型和返回值类型,最后创建一个StructTest对象,并将其转化为指针作为参数,调用函数GetStrcutInfo,最后通过输出数据结构的值来检查是否调用成功:

    from ctypes import *
    
    ARRAY_NUMBER = 20;
    STR_LEN = 20;
    #define type
    INTARRAY20 = c_int * ARRAY_NUMBER;
    CHARARRAY20 = c_char * STR_LEN;
    #define struct
    class StructTest(Structure):
        _fields_ = [
            ("number", c_int),
            ("pChar", c_char_p),
            ("str", CHARARRAY20),
            ("iArray", INTARRAY20)
                   ]
    
    #load dll and get the function object
    dll = cdll.LoadLibrary('hello.dll');
    GetStructInfo = dll.GetStructInfo;
    #set the return type
    GetStructInfo.restype = c_char_p;
    #set the argtypes
    GetStructInfo.argtypes = [POINTER(StructTest)];
    
    objectStruct = StructTest();
    #invoke api GetStructInfo
    retStr = GetStructInfo(byref(objectStruct));
    
    #check result
    print "number: ", objectStruct.number;
    print "pChar: ", objectStruct.pChar;
    print "str: ", objectStruct.str;
    for i,val in enumerate(objectStruct.iArray):
        print 'Array[i]: ', val;
    print retStr;

    总结

    1. 用64位的Python去加载32位的DLL会出错

    2. 以上只是些测试程序,在编写Python过程中尽可能的使用"try Except"来处理异常

    3. 注意在Python与C DLL交互的时候字节对齐问题

    4. 
    ctypes
    库的功能还有待继续探索

    http://www.xuebuyuan.com/1639050.html
  • 相关阅读:
    MATLAB中mexFunction函数的接口规范
    opencv 人脸识别 (一)训练样本的处理
    VS 编程常见错误及解决方法
    在用VC编译下debug和release的什么区别
    OpenCV中Mat的详解
    主成份分析PCA
    人脸识别必读的N篇文章
    opencv有关错误及解决办法
    解决办法:CMake编译时出现“error in configuration process project files may be invalid”
    mybatis 学习笔记(二):mybatis SQL注入问题
  • 原文地址:https://www.cnblogs.com/lwngreat/p/4182235.html
Copyright © 2011-2022 走看看