Files
2025-03-13 16:17:53 +01:00

168 lines
4.9 KiB
C++

#include <Python.h>
#include <err.h>
#include "extapi.hpp"
#ifdef __NT__
#include <windows.h>
#include <psapi.h>
//-------------------------------------------------------------------------
bool ext_api_t::load(qstring *errbuf)
{
QASSERT(30602, lib_path.empty() && lib_handle == nullptr);
// Inspired by https://docs.microsoft.com/en-us/windows/win32/psapi/enumerating-all-modules-for-a-process
HANDLE hProcess = GetCurrentProcess();
HMODULE hMods[1024];
DWORD cbNeeded;
if ( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded) == 0 )
return false;
const void *wanted = (const void *) Py_IsInitialized;
for ( size_t i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
MODULEINFO module_info;
if ( GetModuleInformation(hProcess, hMods[i], &module_info, sizeof(module_info)) )
{
if ( wanted >= module_info.lpBaseOfDll )
{
LPVOID end = (LPVOID) ((const char *) module_info.lpBaseOfDll + module_info.SizeOfImage);
if ( wanted < end )
{
// found module
lib_handle = (void *) hMods[i];
break;
}
}
}
}
if ( lib_handle == nullptr )
return false;
#define BIND_SYMBOL_x(Name, fail) \
do \
{ \
* (FARPROC *) &Name ## _ptr = GetProcAddress( \
(HMODULE) lib_handle, TEXT(#Name)); \
if ( Name ## _ptr == nullptr && fail ) \
{ \
errbuf->sprnt("GetProcAddress(\"%s\") failed: %s", \
#Name, qstrerror(-1)); \
return false; \
} \
} while ( 0 )
#define BIND_SYMBOL(Name) BIND_SYMBOL_x(Name, true)
#define BIND_SYMBOL_WEAK(Name) BIND_SYMBOL_x(Name, false)
BIND_SYMBOL(PyEval_SetTrace);
BIND_SYMBOL(PyRun_SimpleStringFlags);
BIND_SYMBOL(PyRun_StringFlags);
#if PY_MAJOR_VERSION < 3
BIND_SYMBOL(Py_CompileString);
#else
BIND_SYMBOL(Py_CompileStringExFlags);
#endif
BIND_SYMBOL(PyFunction_New);
BIND_SYMBOL(PyFunction_GetCode);
BIND_SYMBOL(_PyLong_AsByteArray);
BIND_SYMBOL_WEAK(PyEval_ThreadsInitialized);
BIND_SYMBOL_WEAK(PyEval_InitThreads);
BIND_SYMBOL_WEAK(Py_NoSiteFlag);
#undef BIND_SYMBOL
return true;
}
//-------------------------------------------------------------------------
void ext_api_t::clear()
{
lib_handle = nullptr;
}
#else
#include <dlfcn.h>
//-------------------------------------------------------------------------
bool ext_api_t::load(qstring *errbuf)
{
if ( !lib_path.empty() && lib_handle != nullptr )
{
return true;
}
// QASSERT(30603, lib_path.empty() && lib_handle == nullptr);
// first, check if we have global symbols
if ( dlsym(RTLD_DEFAULT, "Py_IsInitialized") != nullptr )
lib_handle = RTLD_DEFAULT;
else
{
// otherwise, look for shared library to import from
Dl_info dl_info;
memset(&dl_info, 0, sizeof(dl_info));
int rc = dladdr((void *) Py_IsInitialized, &dl_info);
if ( rc == 0 )
{
*errbuf = "Cannot determine path to shared object";
return false;
}
lib_path = dl_info.dli_fname;
lib_handle = dlopen(lib_path.c_str(), RTLD_NOLOAD | RTLD_GLOBAL | RTLD_LAZY);
if ( lib_handle == nullptr )
{
errbuf->sprnt("dlopen(\"%s\") failed: %s", lib_path.c_str(), qstrerror(-1));
return false;
}
}
#define BIND_SYMBOL(Name) \
do \
{ \
Name ## _ptr = (Name ## _t *) dlsym(lib_handle, #Name); \
if ( Name ## _ptr == nullptr ) \
{ \
errbuf->sprnt("dlsym(\"%s\") failed: %s", #Name, qstrerror(-1)); \
return false; \
} \
} while ( 0 )
BIND_SYMBOL(PyEval_SetTrace);
BIND_SYMBOL(PyRun_SimpleStringFlags);
BIND_SYMBOL(PyRun_StringFlags);
#if PY_MAJOR_VERSION < 3
BIND_SYMBOL(Py_CompileString);
#else
BIND_SYMBOL(Py_CompileStringExFlags);
#endif
BIND_SYMBOL(PyFunction_New);
BIND_SYMBOL(PyFunction_GetCode);
BIND_SYMBOL(_PyLong_AsByteArray);
BIND_SYMBOL(Py_NoSiteFlag);
#undef BIND_SYMBOL
return true;
}
//-------------------------------------------------------------------------
void ext_api_t::clear()
{
if ( lib_handle != nullptr )
{
if ( lib_handle != RTLD_DEFAULT )
dlclose(lib_handle);
lib_handle = nullptr;
}
}
#endif
ext_api_t extapi;