当前位置:   article > 正文

记一次开发实战-对提供接口的C/C++进行二次开发

c++ 二次开发

点击蓝字

9a9f147b94f93fbde21a219e81a7a7f5.png

关注我们

一、需求描述

我有一个USB5538的库和头文件,并通过头文件提供了接口,我想把它更改一下,编译成python可调用的模块。

二、创建工程及其目录

1、创建空项目

c8f635fbfb470c12984831557a1f1d9f.png

ce7a18e115c6c73c1ab3295961c35d5e.png

32d978040e194d88e7cf00dc01995a4b.png

 2、创建目录

a6a1feaf33cbdc2acb653415e3c5dd61.png

d9f636520068ff753871a73adb39928c.png

三、创建文件

1、复制文件并添加

e9511d3a3f007f7a5dbcbb682e1b7f78.png

fb5543eb629bbe717fdc3dae144625b1.png

126612fe8f30a2d296b82c8b928466a0.png

2、添加新文件并写入

7bbbca0cc1f77e53aa9d350e954e5474.png

a44a5f03fde30f075e4a275c19557aeb.png

四、环境配置

1、环境异常情况

4ae3fe451ec45d3aa86fbbe7d5c008eb.png

2、配置环境以消除异常

615c05e7607410097236644473e34ef1.jpeg

0189b238a99e4cfe256e91ab055f28f6.png

194dafc2ceac7981cca398a9d2236db8.png

059c6fd93930e7a49f73222a4744cad7.png

五、运行代码

1、二次封装代码

定义一个接口对象,调用之前的接口,并将方法写入该接口对象即可。

  1. #include <iostream>
  2. using namespace std;
  3. #include "usbpylib.h"
  4. // usbpylib.cpp : 只包括标准包含文件的源文件
  5. // Sys.pch 将作为预编译头
  6. // usbpylib.obj 将包含预编译类型信息
  7. class AutoTest {
  8. //private:
  9. public:
  10. //USB5538数据采集器
  11. HANDLE createUSB5538();
  12. void releaseUSB5538(HANDLE hDevice);
  13. void resetUSB5538(HANDLE hDevice); //复位,相当于与PC重连,等同于重新插上USB
  14. void getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[16]); //bDISts[16]为output参数
  15. void setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[16]); //bDOSts[16]为input参数
  16. int getUSB5538DI_One(HANDLE hDevice, int iDI);
  17. void setUSB5538DO_One(HANDLE hDevice, int iDO, int value);
  18. };
  19. // TODO: 在 STDAFX.H 中
  20. // 引用任何所需的附加头文件,而不是在此文件中引用
  21. HANDLE AutoTest::createUSB5538()
  22. {
  23. return USB5538_CreateDevice(0);
  24. }
  25. void AutoTest::releaseUSB5538(HANDLE hDevice)
  26. {
  27. if (hDevice == INVALID_HANDLE_VALUE)
  28. {
  29. return;
  30. }
  31. USB5538_ReleaseDevice(hDevice);
  32. }
  33. void AutoTest::resetUSB5538(HANDLE hDevice)
  34. {
  35. if (hDevice == INVALID_HANDLE_VALUE)
  36. {
  37. return;
  38. }
  39. USB5538_ResetDevice(hDevice);
  40. }
  41. void AutoTest::getUSB5538DI_All(HANDLE hDevice, BYTE bDISts[])
  42. {
  43. if (hDevice == INVALID_HANDLE_VALUE)
  44. {
  45. return;
  46. }
  47. USB5538_GetDeviceDI(hDevice, bDISts);
  48. }
  49. void AutoTest::setUSB5538DO_All(HANDLE hDevice, BYTE bDOSts[])
  50. {
  51. if (hDevice == INVALID_HANDLE_VALUE)
  52. {
  53. return;
  54. }
  55. USB5538_SetDeviceDO(hDevice, bDOSts);
  56. }
  57. int AutoTest::getUSB5538DI_One(HANDLE hDevice, int iDI)
  58. {
  59. if (hDevice == INVALID_HANDLE_VALUE)
  60. {
  61. return -1;
  62. }
  63. BYTE bDISts[16];
  64. USB5538_GetDeviceDI(hDevice, bDISts);
  65. return bDISts[iDI];
  66. }
  67. void AutoTest::setUSB5538DO_One(HANDLE hDevice, int iDO, int value)
  68. {
  69. if (hDevice == INVALID_HANDLE_VALUE)
  70. {
  71. return;
  72. }
  73. BYTE bDOSts[16];
  74. USB5538_RetDeviceDO(hDevice, bDOSts);//回读输出状态
  75. bDOSts[iDO] = value;
  76. USB5538_SetDeviceDO(hDevice, bDOSts);
  77. }
  78. int main()
  79. {
  80. HANDLE obj1;
  81. BYTE bd[16] = { 0,0,0,0,0,1,1,1, 0,0,0,0,0,1,1,1 };
  82. AutoTest AutoTest1;
  83. //cout << "Hello World";
  84. obj1 = AutoTest1.createUSB5538();
  85. cout << "句柄是\n" << obj1 << "\n";
  86. AutoTest1.getUSB5538DI_All(obj1, bd);
  87. AutoTest1.resetUSB5538(obj1);
  88. AutoTest1.releaseUSB5538(obj1);
  89. //cout << "Hello World";
  90. HANDLE hDevice = AutoTest1.createUSB5538();
  91. if (hDevice == INVALID_HANDLE_VALUE)
  92. {
  93. cout << "create error...." << "\n";
  94. }
  95. BYTE bDOSts[16];
  96. BYTE bDISts[16];
  97. bDOSts[0] = 0;
  98. bDOSts[1] = 1;
  99. bDOSts[2] = 0;
  100. bDOSts[3] = 1;
  101. bDOSts[4] = 0;
  102. bDOSts[5] = 1;
  103. bDOSts[6] = 0;
  104. bDOSts[7] = 1;
  105. bDOSts[8] = 0;
  106. bDOSts[9] = 1;
  107. bDOSts[10] = 0;
  108. bDOSts[11] = 1;
  109. bDOSts[12] = 0;
  110. bDOSts[13] = 1;
  111. bDOSts[14] = 0;
  112. bDOSts[15] = 1;
  113. AutoTest1.setUSB5538DO_All(hDevice, bDOSts);
  114. AutoTest1.getUSB5538DI_All(hDevice, bDISts);
  115. cout << "bDISts是\n" << bDISts << "\n";
  116. }

2、如图,运行正常,说明对原接口的二次封装是有效的

23f488875c374d72748871277b10d5b9.png

六、将原功能改写成接口,供python调用

1、基于原有代码,创建新文件USB5538.cpp编写如下:

  1. #define PY_SSIZE_T_CLEAN // 建议在包含Python.h之前总是定义PY_SSIZE_T_CLEAN。
  2. #include <Python.h> // 打包成python扩展所需要的头文件
  3. #include <iostream>
  4. using namespace std;
  5. //#ifndef _USBPYLIB_H_ // 避免头文件被多次编译
  6. //#define _USBPYLIB_H_
  7. #include "../include/usbpylib.h"
  8. //#endif
  9. // 函数的三种实现方式,C函数通常是通过将Python模块和函数名组合在一起命名的,如模块是Combinations(也是.cpp名称),函数是uniqueCombinations,组成了一个函数名
  10. static PyObject*
  11. USB5538_get(PyObject* self) // 定义功能有三种方式,详细文档(旧文档)请查阅https://www.tutorialspoint.com/python/python_further_extensions.htm
  12. {
  13. //PyLongObject one = USB5538_CreateDevice(0);
  14. //PyAddrPair one = USB5538_CreateDevice(0);
  15. //PyAnySet_Check one = USB5538_CreateDevice(0);
  16. //PyAnySet_CheckExact one = USB5538_CreateDevice(0);
  17. //PyAPI_DATA one = USB5538_CreateDevice(0);
  18. //PyAPI_FUNC one = USB5538_CreateDevice(0);
  19. //PyArena_AddPyObject one = USB5538_CreateDevice(0);
  20. //PyASCIIObject one = USB5538_CreateDevice(0);
  21. //PyBaseObject_Type one = USB5538_CreateDevice(0);
  22. //PyByteArrayObject one = USB5538_CreateDevice(0);
  23. //PyBytes_FromObject one = USB5538_CreateDevice(0);
  24. //PyBytesObject one = USB5538_CreateDevice(0);
  25. //PyObject_AsCharBuffer one = USB5538_CreateDevice(0);
  26. //PyObject_AsReadBuffer one = USB5538_CreateDevice(0);
  27. //PyObject_CallObject one = USB5538_CreateDevice(0);
  28. PyObject_Length one = USB5538_CreateDevice(0);
  29. //CompareObjectHandles one = USB5538_CreateDevice(0);
  30. //PyOS_sighandler_t one = USB5538_CreateDevice(0);
  31. //PyObject one = USB5538_CreateDevice(0);
  32. HANDLE hDevice = USB5538_CreateDevice(0); // 获取句柄
  33. cout << hDevice;
  34. BYTE bd[16] = { 0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1 };
  35. //if (hDevice == INVALID_HANDLE_VALUE)
  36. //{
  37. // return;
  38. //}
  39. BOOL a = USB5538_GetDeviceDI(hDevice, bd); // 获取设备DI状态
  40. USB5538_ReleaseDevice(hDevice); // 释放句柄
  41. return Py_BuildValue("s", "uniqueCombinations() return value (is of type 'string')");
  42. ;
  43. //if (a == true)
  44. //{
  45. // return NULL;
  46. //}
  47. //else
  48. //{
  49. // return 0;
  50. //};
  51. };
  52. /*
  53. 函数的三种实现方式例子:
  54. static PyObject *MyFunction( PyObject *self, PyObject *args ); // METH_VARARGS
  55. static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw); // METH_KEYWORDS
  56. static PyObject *MyFunctionWithNoArgs( PyObject *self ); // METH_NOARGS
  57. */
  58. static char get_docs[] = "获取设备的相关信息\n"; // 随意定义的文档字符串描述
  59. // 方法映射表,方法表是一个简单的PyMethodDef结构数组
  60. static PyMethodDef module_methods[] = {
  61. {"get", (PyCFunction)USB5538_get, METH_NOARGS, get_docs},
  62. { NULL, NULL, 0, NULL }
  63. // 格式解释:{ml_name,ml_meth,ml_flags,ml_doc}
  64. // ml_name:这是Python解释器在Python程序中使用的函数名。
  65. // ml_meth:这必须是函数名。
  66. // ml_flags:函数的三种实现方式,上述例子中已经标明对应字段选择
  67. // ml_doc:可以为空值,四个选项对应的空值分别为:{ NULL, NULL, 0, NULL }
  68. };
  69. // 模块后面加module,比较规范。这个结构必须在模块的初始化函数中传递给解释器。初始化函数必须命名为PyInit_name(),其中name是模块的名称,并且应该是模块文件中定义的唯一非静态项
  70. static struct PyModuleDef USB5538module =
  71. {
  72. PyModuleDef_HEAD_INIT,
  73. "Combinations", /* 模块名称 */
  74. "usage: Combinations.uniqueCombinations(lstSortableItems, comboSize)\n", /* 模块文档*/
  75. -1, /* 模块的每个解释器状态的大小,如果模块在全局变量中保持状态,则为-1。*/
  76. module_methods /* 方法映射表 , 即需要引用定义好的引射表*/
  77. };
  78. // 初始化函数,之前的初始化方法 PyMODINIT_FUNC initModule() 已弃用,新文档见 https://docs.python.org/3/extending/extending.html
  79. PyMODINIT_FUNC PyInit_USB5538(void)
  80. {
  81. return PyModule_Create(&USB5538module); // 它返回一个模块对象,并根据模块定义中的表(PyMethodDef结构的数组)将内置函数对象插入到新创建的模块中。
  82. }

2、尝试进行编译

26d11ce4cb804c9c8d853e8c6fff4f5e.png

3、尝试将该文件打包成python库

新建setup.py文件写入以下内容

  1. from distutils.core import setup, Extension
  2. setup(name='USB5538', version='0.1', ext_modules=[Extension('USB5538', [r'D:\MinGW\projects\USB5538ForPython\source\USB5538.cpp' ])])

打开cmd窗口执行setup.py文件(要进入该文件目录下执行)

  1. python setup.py build
  2. python setup.py install --record files.txt

以及调用其接口,均能成功

bd06ca28a667da30740c53b1204d67e7.png

七、丰富接口

1、将该接口改为传参对象

  1. #define PY_SSIZE_T_CLEAN // 建议在包含Python.h之前总是定义PY_SSIZE_T_CLEAN。
  2. #include <Python.h> // 打包成python扩展所需要的头文件
  3. #include <stdio.h>
  4. #include <iostream>
  5. using namespace std;
  6. //#ifndef _USBPYLIB_H_ // 避免头文件被多次编译
  7. //#define _USBPYLIB_H_
  8. #include "../include/usbpylib.h"
  9. //#endif
  10. // 函数的三种实现方式,C函数通常是通过将Python模块和函数名组合在一起命名的,如模块是Combinations(也是.cpp名称),函数是uniqueCombinations,组成了一个函数名
  11. static PyObject*
  12. USB5538_set(PyObject* self, PyObject* args) // 定义功能有三种方式,详细文档(旧文档)请查阅https://www.tutorialspoint.com/python/python_further_extensions.htm
  13. {
  14. //PyLongObject one = USB5538_CreateDevice(0);
  15. //PyAddrPair one = USB5538_CreateDevice(0);
  16. //PyAnySet_Check one = USB5538_CreateDevice(0);
  17. //PyAnySet_CheckExact one = USB5538_CreateDevice(0);
  18. //PyAPI_DATA one = USB5538_CreateDevice(0);
  19. //PyAPI_FUNC one = USB5538_CreateDevice(0);
  20. //PyArena_AddPyObject one = USB5538_CreateDevice(0);
  21. //PyASCIIObject one = USB5538_CreateDevice(0);
  22. //PyBaseObject_Type one = USB5538_CreateDevice(0);
  23. //PyByteArrayObject one = USB5538_CreateDevice(0);
  24. //PyBytes_FromObject one = USB5538_CreateDevice(0);
  25. //PyBytesObject one = USB5538_CreateDevice(0);
  26. //PyObject_AsCharBuffer one = USB5538_CreateDevice(0);
  27. //PyObject_AsReadBuffer one = USB5538_CreateDevice(0);
  28. //PyObject_CallObject one = USB5538_CreateDevice(0);
  29. PyObject_Length one = USB5538_CreateDevice(0);
  30. //CompareObjectHandles one = USB5538_CreateDevice(0);
  31. //PyOS_sighandler_t one = USB5538_CreateDevice(0);
  32. //PyObject one = USB5538_CreateDevice(0);
  33. int a1;
  34. int a2;
  35. int a3;
  36. int a4;
  37. int a5;
  38. int a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16;
  39. if (!PyArg_ParseTuple(args, "iiiiiiiiiiiiiiii", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11, &a12, &a13, &a14, &a15, &a16))
  40. {
  41. //return Py_BuildValue("s", "参数输入有误,请传递全数字的列表!");
  42. return Py_BuildValue("s", "error!");
  43. }
  44. //return Py_BuildValue("(iiiiiiiiiiiiiiiii)", a1 + a1, a1 - a2, a1+a3);
  45. HANDLE hDevice = USB5538_CreateDevice(0); // 获取句柄
  46. //cout << hDevice << "\n";
  47. BYTE bd[16] = { a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16 };
  48. //BYTE bd[16] = { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 }; // 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  49. USB5538_SetDeviceDO(hDevice, bd);
  50. //BOOL DIstatus = USB5538_GetDeviceDI(hDevice, bd); // 获取设备DI状态
  51. //cout << DIstatus << "\n";
  52. USB5538_ReleaseDevice(hDevice); // 释放句柄
  53. //return Py_BuildValue("s", "恭喜你,在窗口打印设备句柄成功!");
  54. return Py_BuildValue("s", "set success!");
  55. };
  56. /*
  57. 函数的三种实现方式例子:
  58. static PyObject *MyFunction( PyObject *self, PyObject *args ); // METH_VARARGS
  59. static PyObject *MyFunctionWithKeywords(PyObject *self,PyObject *args,PyObject *kw); // METH_KEYWORDS
  60. static PyObject *MyFunctionWithNoArgs( PyObject *self ); // METH_NOARGS
  61. */
  62. //static char get_docs[] = "获取设备的相关信息\n"; // 随意定义的文档字符串描述
  63. static char get_docs[] = "get info of device\n"; // 随意定义的文档字符串描述
  64. // 方法映射表,方法表是一个简单的PyMethodDef结构数组
  65. static PyMethodDef module_methods[] = {
  66. {"set", (PyCFunction)USB5538_set, METH_VARARGS, get_docs},
  67. { NULL, NULL, 0, NULL }
  68. // 格式解释:{ml_name,ml_meth,ml_flags,ml_doc}
  69. // ml_name:这是Python解释器在Python程序中使用的函数名。
  70. // ml_meth:这必须是函数名。
  71. // ml_flags:函数的三种实现方式,上述例子中已经标明对应字段选择
  72. // ml_doc:可以为空值,四个选项对应的空值分别为:{ NULL, NULL, 0, NULL }
  73. };
  74. // 模块后面加module,比较规范。这个结构必须在模块的初始化函数中传递给解释器。初始化函数必须命名为PyInit_name(),其中name是模块的名称,并且应该是模块文件中定义的唯一非静态项
  75. static struct PyModuleDef USB5538module =
  76. {
  77. PyModuleDef_HEAD_INIT,
  78. "USB5538", /* 模块名称 这个只是python调用__name__时展示,即使写错也不会有影响*/
  79. //"USB5538的python接口对象,提供丰富的接口,用于操作USB5538设备\n", /* 模块文档*/
  80. "USB5538 of python interface\n", /* 模块文档*/
  81. -1, /* 模块的每个解释器状态的大小,如果模块在全局变量中保持状态,则为-1。*/
  82. module_methods /* 方法映射表 , 即需要引用定义好的引射表*/
  83. };
  84. // 初始化函数,之前的初始化方法 PyMODINIT_FUNC initModule() 已弃用,新文档见 https://docs.python.org/3/extending/extending.html
  85. PyMODINIT_FUNC PyInit_USB5538(void)
  86. {
  87. return PyModule_Create(&USB5538module); // 它返回一个模块对象,并根据模块定义中的表(PyMethodDef结构的数组)将内置函数对象插入到新创建的模块中。
  88. }

2、验证

如图,验证成功!

b0ad84c3d84a88d2fe523e3fda1ff591.png

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

a093e51feb17ca8b660843894a257093.png

e441ca715f87f5b38cebf9735fd04750.gif

戳“阅读原文”我们一起进步

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号