工做中准备用python 做为脚本语言来实现一些工做因而就研究 能够和c++ 交互的脚本语言 原本一开始用的lua 可是 lua自己API接口不多 要么本身须要重复封装代码 要么c++ 导出 太多地方须要重复造轮子。之因此选择python 是由于python的包多 直接 import 便可食用 好了 废话很少说直接进入正题html
SWIG 是一种软件开发工具,将用 C 编写的程序与各类高级编程语言C++。SWIG 用于不一样类型的目标语言,包括常见的脚本语言,如 Javascript、Perl、PHP、Python、Tcl 和 Ruby。支持的语言列表还包括非脚本语言,如 C#、D、Go 语言、Java(包括 Android、Lua、OCaml、Octave、Scilab 和 R)。还支持几个解释和编译的方案实现(吉勒、MzScheme/Racket)。SWIG 最经常使用于建立高级解释或编译编程环境、用户界面,并做为测试和原型设计 C/C++软件的工具。SWIG 一般用于解析 C/C++接口,并生成上述目标语言调用 C/C++代码所需的"粘合代码"。SWIG 还能够以 XML 的形式导出其解析树。SWIG 是自由软件,SWIG 生成的代码与商业和非商业项目兼容。python
http://www.swig.org/download.htmlc++
下载之后你将获得一个压缩包 swig-4.0.1.tar.gz
我下载的是4.0版本的编程
swig 文档介绍的很详细了 大部分能够在文档中找到答案 下载后解压压缩包获得以下结构的目录 windows
其中 swig.exe 就是咱们须要用到的 首先把这个目录添加的系统环境变量 中 的path
中去 而后能够进入 目录Examples\
下能够看到 不少语言的使用例子 这里咱们进入python
目录能够看到各类c++ 生成python的例子 进入python 目录下后 进入class
目录能够看到 一个很简单 的 c++ 类导出成python 模块的例子编程语言
用 Visual Studio 打开 example.dsp
便可 这里有用的 就两种文件 一种是 你的c++ 源文件 头文件 另一种就是 xxxxx.i的接口文件 这个是 给swig 使用的函数
下面我就简单的用c++给 python 封装一个文件目录监控的例子 来说吧 首先打开 你的 Visual Studio 新建一个项目 选择win32项目 建立一个 win32 动态库项目 开始写你的c++ 代码 个人代码以下 FileDirectoryMonitor.h
工具
#ifndef __FILEDIRECTORYMONITOR_H__ #define __FILEDIRECTORYMONITOR_H__ #include <string> #include <memory> #include <thread> #include <windows.h> class POV :public OVERLAPPED { public: POV() { Internal = InternalHigh = 0; Offset = OffsetHigh = 0; hEvent = NULL; m_bufferSize = 1024; m_pData = new BYTE[m_bufferSize]; memset(m_pData, 0, m_bufferSize); } ~POV() { if (m_pData) { delete[] m_pData; m_pData = nullptr; } } public: LPVOID m_pData; DWORD m_bufferSize; }; class Callback { public: Callback() {}; virtual ~Callback() {}; virtual void run(const char* filename) {}; }; class FileDirectoryMonitor { public: FileDirectoryMonitor(); virtual ~FileDirectoryMonitor(); bool SetMonitorPath(const std::string& strPath, Callback* callBack); void start(); private: std::unique_ptr<std::thread> mMonitorThread; HANDLE hFile; HANDLE hIoCmp; POV* povData; DWORD mCompletionKey; Callback* mCallBack; void MonitorThreadProc(); bool mRuning; }; #endif //__FILEDIRECTORYMONITOR_H__
cpp 代码文件 FileDirectoryMonitor.cpp
开发工具
#include "FileDirectoryMonitor.h" #include <locale> #include <codecvt> FileDirectoryMonitor::FileDirectoryMonitor() :hFile(INVALID_HANDLE_VALUE) ,hIoCmp(INVALID_HANDLE_VALUE) ,mCompletionKey(1) ,mCallBack(nullptr) ,mRuning(true) ,povData(nullptr) { } FileDirectoryMonitor::~FileDirectoryMonitor() { if (mMonitorThread) { if (mMonitorThread->joinable()) { mRuning = false; mMonitorThread->join(); mMonitorThread.reset(); mMonitorThread = nullptr; } } if (povData) { delete povData; povData = nullptr; } } bool FileDirectoryMonitor::SetMonitorPath(const std::string& strPath, Callback* callBack) { bool bResult = false; hFile = CreateFileA(strPath.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == hFile) { return bResult; } if (!callBack) { return bResult; } if (mCallBack) { delete mCallBack; mCallBack = nullptr; } mCallBack = callBack; hIoCmp = CreateIoCompletionPort(hFile, NULL, mCompletionKey, NULL); if (!hIoCmp) { CloseHandle(hFile); return bResult; } povData = new POV(); DWORD dwCbyte = 0; BOOL isSucceed = ReadDirectoryChangesW(hFile, povData->m_pData , povData->m_bufferSize , FALSE , FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE , &dwCbyte, (LPOVERLAPPED)povData , NULL); if (isSucceed) { bResult = true; } return bResult; } void FileDirectoryMonitor::start() { mMonitorThread = std::make_unique<std::thread>(&FileDirectoryMonitor::MonitorThreadProc, this); mMonitorThread->join(); } void FileDirectoryMonitor::MonitorThreadProc() { POV* OverApp = nullptr; DWORD lpNumberOfBytesTransferred = NULL; ULONG_PTR lpCompletionKey = NULL; DWORD dwCbyte = 0; while (mRuning) { BOOL isOK = GetQueuedCompletionStatus(hIoCmp, &lpNumberOfBytesTransferred, &lpCompletionKey, (LPOVERLAPPED*)&OverApp, INFINITE); if (isOK) { //printf("1111\n"); if (!OverApp) { break; } if (OverApp->m_pData) { //printf("2222\n"); DWORD dwNextOffset = 0; auto pnotify = (FILE_NOTIFY_INFORMATION*)(OverApp->m_pData); do { //printf("3333\n"); dwNextOffset = pnotify->NextEntryOffset; if (pnotify->FileNameLength && pnotify->Action == FILE_ACTION_ADDED) { std::wstring filename; filename.assign(pnotify->FileName, pnotify->FileNameLength); //printf("4444\n"); if (mCallBack) { //printf("5555\n"); std::string strFileName = "zh-CN"; typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> F; static std::wstring_convert<F> strCnv(new F(strFileName)); strFileName = strCnv.to_bytes(filename); //printf("6666 \t %s\n",strFileName.c_str()); mCallBack->run(strFileName.c_str()); //printf("7777\n"); } } if (dwNextOffset != 0) { pnotify = (FILE_NOTIFY_INFORMATION*)((BYTE*)pnotify + dwNextOffset); } } while (dwNextOffset != 0); } } memset(OverApp->m_pData, 0, OverApp->m_bufferSize); if (!ReadDirectoryChangesW(hFile, OverApp->m_pData , OverApp->m_bufferSize , FALSE , FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE , &dwCbyte, (LPOVERLAPPED)OverApp , NULL)) { break; } } }
在 Visual Studio 新建一个 xxx.i
的文件 这个是这个项目的 Directory.i
文件测试
%module(directors="1") Directory %include "std_string.i" %{ #include "FileDirectoryMonitor.h" %} %feature("director") Callback; %include "FileDirectoryMonitor.h"
下面咱们来简单介绍下 %module 模块名
这个模块名是 在python中你 import 模块名
的名字 至于为何我这个 里面为何会在 %module后面 带了括号 这个是由于 %module 支持带一些配置信息 我这个带的配置信息就是 导出回调函数模块的 具体能够参考 swig 文档中的 回调函数讲解 %{ #include "FileDirectoryMonitor.h" // 这里是你须要引用的 头文件 %}
至于%include "FileDirectoryMonitor.h" //是给 swig 生成python 模块的 引入的 能够参考文档
%feature("director") Callback; // 导出一个回调函数类 可让python 的类继承 这样你就可在python 中 继承这个 类 来重载实现 你的 回调函数了
想生成这个项目你必须安装了 python 环境 须要在 系统环境变量中 添加 PATHON_INCLUDE
python 的include 目录路径 以及PYTHON_LIB
python 的lib 路径
上面的作好了 须要在 咱们的项目 右键属性 -> C/C++ -> 常规 -> 附加包含目录 中添加 的include 目录路径
以及须要在 咱们的项目 右键属性 -> 连接器 -> 附加库目录 中添加 python 的lib库目录路径 还须要在 属性 -> 连接器 -> 输出文件 中修改 输出文件名 格式以下_模块名.pyd
下面咱们还须要对咱们的 xxxxx.i
的接口文件设置编译生成命令
在你的Visual Studio 项目中 选中 xxxxx.i
文件右键属性 -> 配置属性 -> 常规 -> 项类型 选中 自定义生成工具 而后肯定 在自定义生成工具 -> 常规 -> 命令行 添加 swig.exe -c++ -python "%(FullPath)"
输出 中 添加 $(InputName)_wrap.cxx
而后 选中 xxxxx.i
右键编译 编译后没错误 就把 `xxxxxx_wrap.cxx`` 文件添加到项目中
而后去生成就能够看到 在你项目当前目录下 看到 _模块名.pyd
以及 模块名.py
这个时候就能够在 当前目录下 写一个 测试的 python脚本测试你的 代码了
个人测试代码 run.py
import Directory class pycallback(Directory.Callback): def __init(self): print("1111") def run(self,filename): #print(1111,type(filename)) print(filename) Monitor = Directory.FileDirectoryMonitor() back = pycallback() bresult = Monitor.SetMonitorPath("d:\\pdf\\",back) print(bresult) Monitor.start() print("end")