功能不够用?使用C++编写通达信插件及接入Python(二)
参考:https://zhuanlan.zhihu.com/p/613157262
一、准备工作(参考上一篇)
安装 VS2019
安装pycharm
下载 http://help.tdx.com.cn/book.asp 《通达信DLL函数编程规范.rar》
二、下载python3.x的32位版本,http://www.python.org,随便找个32位版就行了。
我准备下载Windows embeddable package (32-bit),然而下载速度感人,于是参考https://blog.csdn.net/m0_64336780/article/details/123534308
从 https://mirrors.huaweicloud.com/python/ 下载了 python-3.11.3.exe 安装
由于我已经安装了python 64 位的,所以安装后,要调整环境变量,将32位的环境变量调到上面,就切换成32位了。需要63位时,再将64位的环境变量调整到上面即可。
三、从 通达信DLL函数编程规范 里的项目开始
1.修改VS2019,勾选 windows10 SDK
2. 用Visual studio 打开 “TestPluginTCale.dsw”文件
出现“评审项目和解决方案更改” ,直接 确定
出现迁移报告,存在错误
3.解决BUG - 修改项目属性
在解决方案资源管理器中,项目的 TestPluginTCale上右键 属性
在弹出框的 配置属性 c/c++ 常规 中,将 “调试信息格式”的选项更改为“程序数据库(/Zi)”
在 配置属性 c/c++ 代码生成 中 “启用最小重新生成”设为“否(/Gm-)”
在 配置属性 c/c++ 代码生成 中 “启用函数级链接”设为“是(/Gy)”
在 配置属性 链接器 常规 附加库目录
输入 D:\Python\python31132\libs (根据你的32位python安装位置确定)之后,值变为:D:\Python\python31132\libs;%(AdditionalLibraryDirectories)
如果添加后,vs报错,说什么python3x_d找不到,那就在安装目录下的libs(不是lib)里找到python3x.lib,复制一份改个名,改成vs要求的文件名就行了。总之,vs说差什么文件,改成vs要求的文件名就可以了。
四、改写TCalcFuyncSets.cpp如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | #include "stdafx.h" #include "TCalcFuncSets.h" #include "Python.h" //严重注意,一定要include这个。 //生成的dll请拷贝到通达信安装目录的T0002/dlls/内,再在公式管理器进行绑定 //有人老是无法正常绑定,这里给出两种解决方案,任选其一,本人喜欢第二种 //1、不运行快捷方式,直接点开通达信目录里的执行文件 //2、运行快捷方式,但需要将快捷方式里的起始位置清空 void CallFunction( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc, char * funcName) { //填上自己的32位python安装目录,当然,你的python也可以直接装在这个目录下。 Py_SetPythonHome(L "C:\\Python31132" ); //用这个版本的python来执行python文件 Py_Initialize(); //初始化python接口 //初始化使用的变量 PyObject* pModule = NULL; PyObject* pFunc = NULL; PyObject* pName = NULL; //获得绝对路径,保证可以访问到 .py文件 //这里需要注意的时候,运行通达信时,找到的路径是通达信的安装路径,所以需要把子路径补充进去 PyRun_SimpleString( "import os,sys" ); PyRun_SimpleString( "sys.path.append(os.getcwd()+ '/T0002/dlls/')" ); //当前的测试python文件名是TDXPYDLL.py,只需要写文件的名称就可以了。也可以换个名字,但需要把名字改了。 pModule = PyImport_ImportModule( "TDXPYDLL" ); //获取调用的函数 pFunc = PyObject_GetAttrString(pModule, funcName); //定义一个与数组等长的PyList对象数组 PyObject* HList = PyList_New(DataLen); PyObject* LList = PyList_New(DataLen); PyObject* CList = PyList_New(DataLen); //定义一个元组,有四个变量的参数元组 PyObject* paramTuple = PyTuple_New(4); //PyList对象的每个元素赋值PyList_Size(HList),以便传入价格序列 for ( int i = 0; i < DataLen; i++) { PyList_SetItem(HList, i, Py_BuildValue( "f" , pfINa[i])); PyList_SetItem(LList, i, Py_BuildValue( "f" , pfINb[i])); PyList_SetItem(CList, i, Py_BuildValue( "f" , pfINc[i])); } //向python传参数 PyTuple_SetItem(paramTuple, 0, Py_BuildValue( "i" , DataLen)); //第一个参数 PyTuple_SetItem(paramTuple, 1, HList); //1:表示序号。第二个参数。 PyTuple_SetItem(paramTuple, 2, LList); //2:表示序号。第三个参数。 PyTuple_SetItem(paramTuple, 3, CList); //3:表示序号。第四个参数。 //使用C++的python接口调用该函数 PyObject* pReturn = PyObject_CallObject(pFunc, paramTuple); if (pReturn) //类型检查 { for ( int i = 0; i < DataLen; i++) { //PyObject *Item = PyList_GetItem(pReturn, i);//获取List对象中的每一个元素 float result; PyArg_Parse(PyList_GetItem(pReturn, i), "f" , &result); //f表示转换成浮点变量 pfOUT[i] = result; } } ////用完接口得放掉,呼应前面的Py_Initialize(); Py_Finalize(); } void TestPlugin1( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin1" ); } void TestPlugin2( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin2" ); } void TestPlugin3( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin3" ); } void TestPlugin4( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin4" ); } void TestPlugin5( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin5" ); } void TestPlugin6( int DataLen, float * pfOUT, float * pfINa, float * pfINb, float * pfINc) { CallFunction(DataLen, pfOUT, pfINa, pfINb, pfINc, "TestPlugin6" ); } //加载的函数,这里的序号和上面函数对应,这只是绑了六个,想多绑的自己加 PluginTCalcFuncInfo g_CalcFuncSets[] = { {1,(pPluginFUNC)&TestPlugin1}, {2,(pPluginFUNC)&TestPlugin2}, {3,(pPluginFUNC)&TestPlugin3}, {4,(pPluginFUNC)&TestPlugin4}, {5,(pPluginFUNC)&TestPlugin5}, {6,(pPluginFUNC)&TestPlugin6}, {0,NULL}, }; //导出给TCalc的注册函数 BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun) { if (*pFun == NULL) { (*pFun) = g_CalcFuncSets; return TRUE; } return FALSE; } |
结果提示没头文件,python.h
参考:https://blog.csdn.net/JLinkTwo/article/details/87917504 用 pip install python-dev 安装
再参考:https://blog.csdn.net/weixin_44575152/article/details/114186758 对 配置属性 VC++目录 外部包含目录 进行编辑, 加入了 python.h所在目录: D:\Python\python31132\include
生成解决方案
又提示: 无法打开文件“python311_d.lib
于是将D:\Python\python31132\libs下的 python311.lib 复制 为 python311_d.lib
终于成功了
到了这里, Dll写完了,编译成32位TestPluginTCale.dll放到T0002/dlls目录里。然后创建一个TDXPYDLL.py,该文件同样需要放在T0002/dlls内。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | def TestPlugin1(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result def TestPlugin2(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result def TestPlugin3(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result def TestPlugin4(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result def TestPlugin5(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result def TestPlugin6(N: int , H: list, L: list, C: list): for i in range(1, N): result[i] = i return result |
按上一篇 绑定DLL,写demo公式,结果通达信死机
后来发现 dll 源文件 中有一句忘记改了:
Py_SetPythonHome(L"C:\\Python31132"); //用这个版本的python来执行python文件
改为Py_SetPythonHome(L"D:\\Python\\python31132");
重新生成dll,替换,不要从快捷方式而是从所在目录中启动TdxW.exe,看似成功了,python脚本似乎也运行了。然而得不到输出。
又参照网贴,将TestPlugin2改为如下代码:
1 2 3 4 5 6 | def TestPlugin2(N: int , H: list, L: list, C: list): result=[] for i in range(1, N): temp = i * 6.0 result.append(temp) return result |
终于成功了
上面的temp也可以:temp = (H[i]+L[i]+C[i])*1.0
说明:在python代码中,可以 import os
然后用os.mkdir('你的目录')在通达信运行目录中生成文件夹
或者用
1 2 | log = open( 'r.txt' , 'a' ) print(“相关数据”, file=log) |
更明显地看到效果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2020-04-17 python查看乱码
2020-04-17 使用 Python 查看局域网内存活主机