Browse Source

注意:如果调用的Python脚本有包含其他py模块时,这个py模块必须在环境变量的目录中,否则会调用失败(而用pycharm之类的则成功。)

sat23 4 năm trước cách đây
mục cha
commit
52cb2ccd89

+ 156 - 87
SATHelper/SATHelper/CallPython.cpp

@@ -1,98 +1,117 @@
 #include "StdAfx.h"
 #include "CallPython.h"
+#include "CharEncoding.h"
 
-namespace CallPython {
-	void InitPython()
-	{
-		if (!Py_IsInitialized())
-			Py_Initialize();
-	}
+CCallPython::CCallPython()
+{
+	_state = PyGILState_Ensure();
+}
 
-	void FreePython()
-	{
-		Py_Finalize();
-	}
+CCallPython::~CCallPython()
+{
+	PyGILState_Release(_state);
+}
 
-	void PySetItem(PyObject* args, _variant_t var, int nIndex)
-	{
-		if (args == NULL || nIndex < 0)
-			return;
+void CCallPython::Init()
+{
+	Py_Initialize();
+	if (!Py_IsInitialized())
+		return;
+	// 不用多线程,不用开启下面功能;
+	// 初始化线程支持	
+	//PyEval_InitThreads();
+	// 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
+	//PyEval_ReleaseThread(PyThreadState_Get());
+}
 
-		switch (var.vt)
-		{
+void CCallPython::Free()
+{
+	// 保证子线程调用都结束后
+	PyGILState_Ensure();
+	Py_Finalize();
+}
+
+void PySetItem(PyObject* args, _variant_t var, int nIndex)
+{
+	if (args == NULL || nIndex < 0)
+		return;
+
+	PyObject* pValue;
+	switch (var.vt)
+	{
 		case VT_BSTR:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("s", var.bstrVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("u", var.bstrVal));
 			break;
 		}
 		case VT_LPSTR:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("s", var.bstrVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("s", var.bstrVal));
 			break;
 		}
 		case VT_I1:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("b", var.cVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("b", var.cVal));
 			break;
 		}
 		case VT_I2:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("h", var.iVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("h", var.iVal));
 			break;
 		}
 		case VT_I4:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("i", var.lVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("i", var.lVal));
 			break;
 		}
 		case VT_I8:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("k", var.lVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("k", var.lVal));
 			break;
 		}
 		case VT_INT:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("i", var.intVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("i", var.intVal));
 			break;
 		}
 		case VT_UI1:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("B", var.cVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("B", var.cVal));
 			break;
 		}
 		case VT_UI2:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("H", var.iVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("H", var.iVal));
 			break;
 		}
 		case VT_UI4:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("I", var.lVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("I", var.lVal));
 			break;
 		}
 		case VT_UI8:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("K", var.lVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("K", var.lVal));
 			break;
 		}
 		case VT_UINT:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("I", var.intVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("I", var.intVal));
 			break;
 		}
 		case VT_R4:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("f", var.fltVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("f", var.fltVal));
 			break;
 		}
 		case VT_R8:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("f", var.dblVal));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("f", var.dblVal));
 			break;
 		}
 		case VT_BOOL:
 		{
-			PyTuple_SetItem(args, nIndex, Py_BuildValue("b", (var.boolVal == false) ? 0 : 1));
+			PyTuple_SetItem(args, nIndex, pValue = Py_BuildValue("b", (var.boolVal == false) ? 0 : 1));
 			break;
 		}
 		default:
@@ -100,65 +119,115 @@ namespace CallPython {
 			TRACE("UnSupport type for Python: %d\n", var.vt);
 			break;
 		}
-		}
+
+		if (pValue)
+			Py_DECREF(pValue);
 	}
+}
 
-	PyObject* CallPython(std::string strPyPath, std::string strPyFuncName, int argc, ...)
-	{
-		if (!Py_IsInitialized())
-			Py_Initialize();
-
-		if (!PathFileExists(strPyPath.c_str()) || !strPyFuncName.size())
-			return NULL;
-
-		TCHAR szDrive[_MAX_DRIVE] = { 0 };
-		TCHAR szDir[_MAX_DIR] = { 0 };
-		TCHAR szExt[_MAX_EXT] = { 0 };
-		TCHAR szFilename[_MAX_FNAME] = { 0 };
-		TCHAR szScriptDir[MAX_PATH] = { 0 };
-		_tsplitpath_s(strPyPath.c_str(), szDrive, szDir, szFilename, szExt);
-		_stprintf_s(szScriptDir, _T("%s%s"), szDrive, szDir);
-		int len = _tcslen(szScriptDir);
-		for (int i = 0; i < len; i++) {
-			if (szScriptDir[i] == '\\')
-				szScriptDir[i] = '/';
-		}
-
-		if (szScriptDir[0] == '\0')
-			_tcscpy_s(szScriptDir, _T("./"));
-
-		TCHAR szExecuteDir[MAX_PATH] = { 0 };
-		_stprintf_s(szExecuteDir, _T("sys.path.append('%s')"), szScriptDir);
-		PyRun_SimpleString("import sys");
-		PyRun_SimpleString(szExecuteDir);
-
-		PyObject* pModule = PyImport_ImportModule(szFilename);
-		if (!pModule)
-			return NULL;
-
-		PyObject* pFunc = PyObject_GetAttrString(pModule, strPyFuncName.c_str());
-		if (!pFunc || !PyCallable_Check(pFunc))
-			return NULL;
-
-		PyObject* pRet = NULL;
-		if (argc != 0) {
-			va_list ap;
-			va_start(ap, argc);
-			PyObject* args = PyTuple_New(argc);
-			if (!args) {
-				va_end(ap);
-				return NULL;
-			}
-
-			for (int i = 0; i < argc; i++) {
-				PySetItem(args, va_arg(ap, _variant_t), i);
-			}
+PyObject* CCallPython::CallPython(std::string strPyPath, std::string strPyFuncName, int argc, ...)
+{
+	if (!Py_IsInitialized())
+		Py_Initialize();
+
+	if (!PathFileExists(strPyPath.c_str()) || !strPyFuncName.size())
+		return NULL;
+
+	TCHAR szDrive[_MAX_DRIVE] = { 0 };
+	TCHAR szDir[_MAX_DIR] = { 0 };
+	TCHAR szExt[_MAX_EXT] = { 0 };
+	TCHAR szFilename[_MAX_FNAME] = { 0 };
+	TCHAR szScriptDir[MAX_PATH] = { 0 };
+	_tsplitpath_s(strPyPath.c_str(), szDrive, szDir, szFilename, szExt);
+	_stprintf_s(szScriptDir, _T("%s%s"), szDrive, szDir);
+	int len = _tcslen(szScriptDir);
+	for (int i = 0; i < len; i++) {
+		if (szScriptDir[i] == '\\')
+			szScriptDir[i] = '/';
+	}
+
+	if (szScriptDir[0] == '\0')
+		_tcscpy_s(szScriptDir, _T("./"));
+
+	TCHAR szExecuteDir[MAX_PATH] = { 0 };
+	_stprintf_s(szExecuteDir, _T("sys.path.append('%s')"), szScriptDir);
+	PyRun_SimpleString("import sys");
+	PyRun_SimpleString("sys.path.append('./')");
+	PyRun_SimpleString("reload(sys)");
+	PyRun_SimpleString(szExecuteDir);
+	_stprintf_s(szExecuteDir, _T("reload('%s')"), szScriptDir);
+	PyRun_SimpleString(szExecuteDir);
+
+	PyObject* args = NULL;
+	PyObject* pRet = NULL;
+	PyObject* pFunc = NULL;
+	PyObject* pModule = PyImport_ImportModule(szFilename);
+	if (!pModule)
+		goto over;
+
+	pFunc = PyObject_GetAttrString(pModule, strPyFuncName.c_str());
+	if (!pFunc || !PyCallable_Check(pFunc))
+		goto over;
+
+	if (argc != 0) {
+		va_list ap;
+		va_start(ap, argc);
+		args = PyTuple_New(argc);
+		if (!args) {
 			va_end(ap);
-			pRet = PyObject_CallObject(pFunc, args);
+			goto over;
 		}
-		else
-			pRet = PyEval_CallObject(pFunc, NULL);
 
-		return pRet;
+		for (int i = 0; i < argc; i++) {
+			PySetItem(args, va_arg(ap, _variant_t), i);
+		}
+		va_end(ap);
+		pRet = PyObject_CallObject(pFunc, args);
+	}
+	else
+		pRet = PyEval_CallObject(pFunc, NULL);
+
+over:
+	if (args)
+		Py_DECREF(args);
+
+	if (pFunc)
+		Py_DECREF(pFunc);
+
+	if (pModule)
+		Py_DECREF(pModule);	
+
+	return pRet;
+}
+
+int CCallPython::GetIntegerValue(PyObject* pValue)
+{
+	int value = 0;
+	if (pValue) {
+		PyArg_Parse(pValue, "i", &value);
+	}
+
+	return value;
+}
+
+std::string CCallPython::GetUnicodeString(PyObject* pValue)
+{
+	std::string strValue;
+	if (pValue) {
+		char* pszValue;
+		PyArg_Parse(pValue, "s", &pszValue);
+		CharEncoding::UNICODE2ASCII((LPWCH)pszValue, strValue);
+	}
+	return strValue;
+}
+
+std::string CCallPython::GetUTF8String(PyObject* pValue)
+{
+	std::string strValue;
+	if (pValue) {
+		char* pszValue;
+		PyArg_Parse(pValue, "s", &pszValue);
+		CharEncoding::UTF82ASCII(pszValue, strValue);
 	}
-}
+	return strValue;
+}

+ 17 - 7
SATHelper/SATHelper/CallPython.h

@@ -4,13 +4,23 @@
 #include "Python.h"
 #include <comdef.h>
 
-namespace CallPython {
-	// 初始化Python调用环境;
-	extern "C" void InitPython();
+// 使用垫片类处理;
+class CCallPython {
+	PyGILState_STATE _state;
+public:
+	CCallPython();
+	~CCallPython();
+
+	static void Init();
+	static void Free();
+
+	
 	// 调用Python脚本指定函数;
-	extern "C" PyObject * CallPython(std::string strPyPath, std::string strPyFuncName, int argc, ...);
-	// 释放Python调用环境;
-	extern "C" void FreePython();
+	PyObject* CallPython(std::string strPyPath, std::string strPyFuncName, int argc, ...);
+
+	int GetIntegerValue(PyObject *pValue);
+	std::string GetUnicodeString(PyObject* pValue);
+	std::string GetUTF8String(PyObject* pValue);
+};
 
-}
 #endif

+ 2 - 3
SATHelper/SATHelper/SATHelper.cpp

@@ -122,8 +122,6 @@ BOOL CSATHelperApp::InitInstance()
 	}
 #endif
 
-	CallPython::InitPython();
-
 	// 示例;
 	//PyObject * pRet = CallPython("F:\\SAT\\SAT_API\\ssat_sdk\\device_manage\\testWizardClient.py", "API_UsbSwitch", 1, _variant_t(1));
 
@@ -187,6 +185,7 @@ BOOL CSATHelperApp::InitInstance()
 	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
 	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)
 
+	CCallPython::Init();
 
 	InitContextMenuManager();
 	InitShellManager();
@@ -249,7 +248,7 @@ int CSATHelperApp::ExitInstance()
 	AfxOleTerm(FALSE);
 	Gdiplus::GdiplusShutdown(m_gdiplusToken);
 	g_iocp.Stop();
-	CallPython::FreePython();
+	CCallPython::Free();
 	return CWinAppEx::ExitInstance();
 }
 

+ 8 - 6
SATHelper/SATHelper/UpgradeWnd.cpp

@@ -202,18 +202,20 @@ void CUpgradeWnd::OnUpgradeBtnClick()
 		WritePrivateProfileString("SATHelper", "ftp_password", strFtpPassword.GetString(), Global::g_szConfig);
 	}
 
+	CCallPython pycall;
 	TCHAR szPath[MAX_PATH] = {0};
 	_stprintf_s(szPath, _T("%sscripts\\TVUpgrade.py"), Global::g_szCurModuleDir);
-	PyObject *pRet = CallPython::CallPython(szPath, _T("API_TVUpgrade"), 3, _variant_t(strPath.GetString()), _variant_t(strFtpUser.GetString()), _variant_t(strFtpPassword.GetString()));
+	PyObject *pRet = pycall.CallPython(szPath, _T("API_TVUpgrade"), 3, _variant_t(strPath.GetString()), _variant_t(strFtpUser.GetString()), _variant_t(strFtpPassword.GetString()));
 	if (pRet == NULL)
 	{
 		AfxMessageBox(_T("运行失败"));
 	}
 	else
-	{
-		TCHAR szValue[MAX_PATH] = {0};
-		PyArg_Parse(pRet, "s", &szValue);
-		AfxMessageBox(szValue);
+	{		
+		AfxMessageBox(pycall.GetUTF8String(pRet).c_str());
+
+		if (pRet)
+			Py_DECREF(pRet);
 	}
 
 }
@@ -300,7 +302,7 @@ void CUpgradeWnd::SetCtrlStyle()
 	m_check_remember.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;
 	m_check_remember.SizeToContent();*/
 
-	m_edit_path.EnableFileBrowseButton();
+	m_edit_path.EnableFolderBrowseButton();
 	m_edit_path.EnableFileBrowseButton(_T(""), _T("Image Files(*.img)|*.img"
 		"|Zip Files(*.zip)|*.zip"
 		"|Rar Files(*.rar)|*.rar"