我正在创建一个基于SFL(服务框架库)的服务。当我从控制台工作时,没问题,但是当我通过“sc start MyService”将其作为服务运行时,在调用 Py_Initialize 等时会发出致命错误。
当程序崩溃时,将以下行发送到调试器:
致命的Python错误:无法获取文件系统编码的Python编解码器
sc 查询 MyService 输出:
SERVICE_NAME: MyService
TYPE : 10
WIN32_OWN_PROCESS STATE : 1
STOPPED WIN32_EXIT_CODE : 1077 (0x435)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
#include "SflBase.h"
namespace nsSFL
{
const CMyService* SflGetServiceApp(void)
{
static T theApp;
return &theApp;
}
}
int _tmain( int argc, LPTSTR* argv )
{
CMyService* pApp = const_cast<CMyService*>( SFL_NS SflGetServiceApp() );
nsSFL::CServiceRoot* pServiceMap[] = {
nsSFL::CServiceProxyT<CMyService, 0>::Construct2((TService*)NULL, L"CMyService")
};
int retMain = -1;
if(pApp->PreMain(argc, argv))
retMain = pApp->Main( argc, argv, pServiceMap, ARRAYSIZE(pServiceMap));
pApp->PostMain();
return retMain;
}
BOOL CMyService::PreMain(int argc, LPTSTR* argv)
{
if (!InitInstance(argc, argv))
{
return FALSE;
}
return TRUE;
}
BOOL CMyService::InitInstance(DWORD argc, LPTSTR* lpszArgv)
{
if (!AfxWinInit(::GetModuleHandle(nullptr), nullptr, ::GetCommandLine(), 0))
{
return FALSE;
}
{
PyPreConfig preconfig;
PyPreConfig_InitIsolatedConfig(&preconfig);
preconfig.utf8_mode = true;
status = Py_PreInitialize(&preconfig);
pystatus_exit_on_error(status);
}
// auto pythonPath = L"%localappdata%\\Programs\\Python\\Python38\\python.exe";
auto pythonPath = L"C:\\Program Files\\Python38\\python.exe";
Py_SetPythonHome(pythonPath);
Py_Initialize(); // print "Fatal Python error" only then work as service
}
项目属性:C++20、SDK Windows 10.0.20348.0、Visual Studio 2022 (v143)、python 3.8,均为 x64,boost 1.77
根据这个问题我尝试取消设置
PYTHONPATH
和PYTHONHOME
,但系统中不可用,所以我设置了这些变量(仍然错误),并从环境变量中取消设置它们(仍然错误)。
根据那个问题我尝试分配Py_SetPythonHome,但不是“C:\ Program Files \ Python38 \ python.exe”的路径,也不是“%localappdata%\ Programs \ Python \ Python38 \ python.exe”没有以任何方式影响错误。 使用 PyConfig_InitIsolatedConfig/PyConfig_InitPythonConfig 也没有解决问题。
我认为问题与 LocalSystem 的一些限制有关,尽管 NetworkService 根本拒绝启动并且 LocalService 不适合,因为我需要使用端口。也许我应该设置某种访问权限,但我不知道如何甚至在哪里可以找到信息。
我决定尝试填写配置器的所有文本变量,结果这就是答案:
wchar_t pythonPath[MAX_PATH * 3];
wchar_t pythonExe[MAX_PATH];
wchar_t pythonHome[] = L"%localappdata%\\Programs\\Python\\Python38"; // L"C:\\Program Files\\Python38";
(void)swprintf_s(pythonPath, L"%s\\Lib;%s\\DLLs;%s\\Lib\\site-packages", pythonHome, pythonHome, pythonHome);
PathCombineW(pythonExe, pythonHome, L"python.exe");
PyConfig config;
PyConfig_InitPythonConfig(&config);
PyConfig_SetString(&config, &config.executable, pythonExe);
PyConfig_SetString(&config, &config.home, pythonHome);
PyConfig_SetString(&config, &config.pythonpath_env, pythonPath);
PyStatus status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status) || !Py_IsInitialized())
{
CMyService::LogPythonError(L"Python initialization failed");
CMyService::LogTextEvent(pythonPath);
PyConfig_Clear(&config);
return false;
}
PyConfig_Clear(&config);