工做中準備用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")