CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

C++给python写扩展库

在上文中实现了自动发送消息,接收消息,C++ DLL注入微信实现自动接收、发送消息620 赞同 · 117 评论文章

其中,我们写了InjectDll给Python调用但是我现在觉得,又要用ctypes载入DLL,调用个函数都要几行代码,还无法导出类太麻烦,不简洁所以决定把这个注入程序的DLL写成一个Python模块(module),到时候直接import就能用,岂不美哉。

以前都是做完再写文章出来,这次就抽空闲时间边学边做,边写边更新,有空就更一下,把踩到的坑都记上Python本来也就是C程序实现的(一般来说),用C给Python调用应该不难,甚至可以说是理所当然的上网查了查,每一个教程代码前面都是要先包含Python.h的,看来这个文件是Python对象的内核啊。

好,立马写上,#include然而,vs却说无法打开这个文件这红色的波浪线给我当头一棒,无论我怎么改,它愣是无法打开无法打开这不应该呀我去mingw32里头文件找了找,还真没有不可能,于是我打开了尘封的everything搜索,

还是一如既往的快其中有个C盘的,好像是Python安装目录,打开一看果然是。

原来在Python目录里的include文件夹。怎么能导入它呢回到vs,解决方案那栏右键项目属性,到VC++目录的包含目录

把找到的Python.h文件所在路径加上去。回到代码,红波浪线没了,搞定第一坑。

下面添加C函数到扩展模块。本来,我们要从DLL导出使用的函数,是都写在了dllexport里面,

既然这些是我们要在Python中使用的函数,那么就先挑一个试验吧。就用 @周星星 提供的GetPidByProcessName作模块的第一个函数。参考官方doc,

文档的示例函数是传入一个字符串,返回整数对象,刚好我们的GetPidByProcessName也是传入字符串返回整数staticPyObject*_GetPidByProcessName(PyObject。

*self,PyObject*args){constwchar_t*command;intsts;if(!PyArg_ParseTuple(args,”ws”,&command))returnNULL;

sts=GetPidByProcessName(command);returnPyLong_FromLong(sts);}然后定义方法表:staticPyMethodDefSpamMethods[]={

{“GetPidByName”/*给Python使用的函数名*/,_GetPidByProcessName/*实际要调用的函数*/,METH_VARARGS,”Get pid from its name.”

/*函数的解释说明*/},{NULL,NULL,0,NULL}/* Sentinel */};这个方法表必须被模块定义结构所引用static struct PyModuleDef injectmodule = { PyModuleDef_HEAD_INIT, “injectwechat”, /* 模块名 */ “A module used to inject the dll to xxx.”, /* 模块文档 */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ SpamMethods };。

然后定义模块初始化函数:PyMODINIT_FUNC PyInit_injectwechat(void) { return PyModule_Create(&injectmodule); }注意,初始化函数的定义名称一定要是

PyInit_加上模块名在main里写上import_inittab不然初始化函数不会自动调用int main(int argc, char* argv[]) { wchar_t* program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) { fprintf(stderr, “Fatal error: cannot decode argv[0]\n”); exit(1); } /* Add a built-in module, before Py_Initialize */ if (PyImport_AppendInittab(“spam”, PyInit_injectwechat) == -1) { fprintf(stderr, “Error: could not extend in-built modules table\n”); exit(1); } /* Pass argv[0] to the Python interpreter */ Py_SetProgramName(program); /* Initialize the Python interpreter. Required. If this step fails, it will be a fatal error. */ Py_Initialize(); /* Optionally import the module; alternatively, import can be deferred until the embedded script imports it. */ PyObject* pmodule = PyImport_ImportModule(“spam”); if (!pmodule) { PyErr_Print(); fprintf(stderr, “Error: could not import module spam\n”); } PyMem_RawFree(program); return 0; }。

现在可以执行链接命令了在VS的视图,终端,打开开发者命令提示,然后把路径转到dllmain.cpp的地方cd InjectDll输入命令cl /LD dllmain.cpp -I C:\Users\Administrator\AppData\Local\Programs\Python\Python38\include C:\Users\Administrator\AppData\Local\Programs\Python\Python38\libs\python38.lib。

_I 后面的两个参数分别是Python的include文件夹路径,和python38.lib[1]所在路径。按下ENTER后,炸出一堆error。

error C2664而且还是乱码看起来像是参数类型不符,但是写DLL却没事怎么写pyd就有事了呢,不管,就按他照办吧勉强读出来的意思是,第一个参数传入的是“PTSTR”与函数所约定的”wchar_t*“不同。

那就强转呗一一把所有的error参数全部加上强制转换此后又出现了函数调用约定的问题,一堆_imp,再加上乱码,是根本看不懂没办法,可能是因为我直接在InjectDll上改,或者是链接命令就不对那就再新开一个项目,就叫pypackage吧,用另一种方法。

把代码搬过来也把模块名改成inject了#include #include #include #define PY_SSIZE_T_CLEAN #include int GetPidByProcessName(const wchar_t* ProcessName) { // get a snapshot of all the process in the system. void* ProcessAll = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); // compare the process name in the snapshot to find pid PROCESSENTRY32W processInfo = { 0 }; processInfo.dwSize = sizeof(PROCESSENTRY32W); while (Process32NextW(ProcessAll, (LPPROCESSENTRY32W)&processInfo)) { if (wcscmp(ProcessName,processInfo.szExeFile) == 0) { return processInfo.th32ProcessID; } } return 0; } static PyObject* spam_system(PyObject* self, PyObject* args) { const Py_UNICODE* command; int sts; if (!PyArg_ParseTuple(args, “u”, &command)) return NULL; sts = GetPidByProcessName(command); return PyLong_FromLong(sts); } static PyMethodDef injectMethods[] = { {“system”, spam_system, METH_VARARGS, “Execute a shell command.”}, {NULL, NULL, 0, NULL} /* Sentinel */ }; static struct PyModuleDef injectmodule = { PyModuleDef_HEAD_INIT, “inject”, /* name of module */ “run cmd”, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ injectMethods }; extern “C” PyMODINIT_FUNC PyInit_inject(void) { return PyModule_Create(&injectmodule); } int main(int argc, char* argv[]) { wchar_t* program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) { fprintf(stderr, “Fatal error: cannot decode argv[0]\n”); exit(1); } /* Add a built-in module, before Py_Initialize */ if (PyImport_AppendInittab(“inject”, PyInit_inject) == -1) { fprintf(stderr, “Error: could not extend in-built modules table\n”); exit(1); } /* Pass argv[0] to the Python interpreter */ Py_SetProgramName(program); /* Initialize the Python interpreter. Required. If this step fails, it will be a fatal error. */ Py_Initialize(); /* Optionally import the module; alternatively, import can be deferred until the embedded script imports it. */ PyObject* pmodule = PyImport_ImportModule(“inject”); if (!pmodule) { PyErr_Print(); fprintf(stderr, “Error: could not import module inject\n”); } PyMem_RawFree(program); return 0; }

然后在项目源码的文件夹新开一个setup.py

写上fromdistutils.coreimportsetup,Extensionmodule1=Extension(inject,#模块名sources=[pypackage.cpp])#源文件setup

(name=PackageName,version=1.0,description=This is a demo package,ext_modules=[module1])目前一切顺利,开始执行生成命令。

在当前文件夹shift+右键,点出“在此处打开命令提示符”。输入命令python setup.py build

完成后,当前目录出现了一个build文件夹。打开,

点第一个lib,里面有一个pyd,这个就是我们生成的模块了现在试用一下,在pyd的旁边创建一个py文件,里写着import inject用IDLE运行运行后,在当前IDLE没有报错,说明已经导入了我们写的C++库!。

用下函数:

好的可以用现在去改一下名字staticPyObject*spam_getpid(PyObject*self,PyObject*args){constPy_UNICODE*command;intsts;if

(!PyArg_ParseTuple(args,”u”,&command))returnNULL;sts=GetPidByProcessName(command);returnPyLong_FromLong

(sts);}staticPyMethodDefinjectMethods[]={{“getpid”,spam_getpid,METH_VARARGS,”input its name and return its pid.”

},{NULL,NULL,0,NULL}/* Sentinel */};关了(或按Ctrl+F6重启IDLE)IDLE,重新生成。

接下来把其他函数也搬过来。参考^名称各有不同,看Python版本而定,但格式相同

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容