刚开始拿到这个任务当然是想直接将python打包成dll给c#调用,然后开始搜索各种将Python打包成dll的资料,搜到了pyinstaller等等,发现最多能打包成exe,打包成dll需要将这个python解释器给干进去,这方面资料也比较少。 开始考虑直接用C#调用python。看到了ironpython,坑爹的是里面嵌入的是2.7版本,而我是用python3.5利用了tensorflow搭建的神经网络。tensorflow支持的最低版本是3.5。遂弃之。 最后考虑用C++先调python,然后将此c++封装成dll,再给c#使用。按照这个思路开始,c++调用python的资料不胜枚举,在此感谢各位无私分享的人们。c#调x64版的python3.5大致步骤如下: (1)配置环境,主要是三个地方,如下三图所示 ![这里写入上面那个libs文件下的对应的pythonxx.lib的名字(例如我的就是python35.lib)] 
( 2 ) 直接安照套路来编写c++主函数
include “stdafx.h”
include
include
include
using namespace std;
int mian(int argc ,char *argv[]) {
// 初始化Python
//在使用Python系统前,必须使用Py_Initialize对其
//进行初始化。它会载入Python的内建模块并添加系统路
//径到模块搜索路径中。这个函数没有返回值,检查系统
//是否初始化成功需要使用Py_IsInitialized。
Py_Initialize();
// 检查初始化是否成功
if (!Py_IsInitialized()) {
cout << "Initialized failed !" << endl;
return -1;
}
// 添加当前路径
//把输入的字符串作为Python代码直接运行,返回0
//表示成功,-1表示有错。大多时候错误都是因为字符串
//中有语法错误。
PyRun_SimpleString("import sys"); //PyRun_SimpleString这个语句可以直接执行fu
PyRun_SimpleString("print ('---import sys---')");
PyRun_SimpleString("sys.path.append('./')");
//PyRun_SimpleString("print(sys.path)");
PyObject *pName = NULL, *pModule = NULL, *pDict = NULL, *pFunc = NULL, *pArgs = NULL;
// 载入名为Screen-classifier的python脚本
printf("Finding python file Screen-classifier......\n");
pName = PyUnicode_FromString("Screen-classifier");
pModule = PyImport_Import(pName);
if (!pModule) {
printf("can't find python file");
getchar();
//return -1;
}
pDict = PyModule_GetDict(pModule);
if (!pDict) {
//return -1;
cout << "Get functions failed !" << endl;
}
找出函数名为ScreenDetectDefect的函数
printf("Finding detect function......\n");
pFunc = PyDict_GetItemString(pDict, "ScreenDetectDefect");
if (!pFunc || !PyCallable_Check(pFunc)) {
printf("can't find function ScreenDetectDefect");
getchar();
//return -1;
}
// 参数进栈
*pArgs;
pArgs = PyTuple_New(3);
// PyObject* Py_BuildValue(char *format, ...)
// 把C++的变量转换成一个Python对象。当需要从
// C++传递变量到Python时,就会使用这个函数。此函数
// 有点类似C的printf,但格式不同。常用的格式有
// s 表示字符串,
// i 表示整型变量,
// f 表示浮点数,
// O 表示一个Python对象。
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", mode));
cout << "AA" << endl;
string path="D:\VC++Program\Csharpcalldll\Csharpcalldll\bin\Debug"
//注意,下面构建python的字符串类型值的时候,不可直接传入c++ string 类的对象,需要使用string类的函数c_str将其转化为真正的string传进去才行。
PyTuple_SetItem(pArgs, 1, Py_BuildValue("s", path_s.c_str()));
cout << "BB" << endl;
PyTuple_SetItem(pArgs, 2, Py_BuildValue("i", imid));
// 调用Python函数
PyObject_CallObject(pFunc, pArgs);
//关闭Python
Py_Finalize();
}
(3)上述程序调试成功之后,将其改为函数形式,并将其打包成dll,主要步骤如下: 1.新建项目,选择c++下面的windows桌面向导,如下 点击确定,然后选择dll,以及空项目和预编译头,如下: 建好之后,将第二步代码整体考进去,把main主函数改成自己想要改成的函数名字以便后续调用。比如我就改成了screendetect(int mode,char*path,int imid)。有一种情况肯出错,就是通过此种方式新建的工程下,源文件中因为#include “stdafx.h”这个语句会导致保持,此刻不要惊慌,按照如下补救措施: 2.生成即可。成功了会有如下的输出: 刚开始可能有种情况就是只会有dll生成,此时应该配置按照如下方式使其能够生成.lib文件。首先新建一个def文件(直接新建c++文件,然后将其后缀改成def即可)然后里面写入如下如所示内容,前两行不动,第三行上一步中将主函数改成 的那个函数(也即打包成dll后需要被调用的那个/那些函数),如我的就是sceendetect。 然后在项目属性的链接器的输入一栏中模拟定义块的地方写入刚才新建的def文件的名字。如下所示: 然后点击生成-》重新生成解决方案,即可得到dll和lib文件。 (4)用c#调用生成好的dll文件 很简单,按照下面模板即可: using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks;
namespace CsharpcCallDll { class Program { //下面加粗地方换成上面所生成的dll所在目录。 [DllImport(@“D:\VC++Program\DllTestScreenTest\x64\Debug\DllTestScreenTest.dll”)] //此处声明你即将调用的函数 extern static int screendetect(int mode,string path, int imid); static void Main(string[] args) { screendetect(1, “D:\ZZFinallyTest\Picture\”, 49); } } } 结束。
|