I have seen Adding symbolic constants with hex values to Python extension module and I am trying to reproduce this effect:
#include <Python.h>
#include <Windows.h>
static PyObject * sys_shutdown(PyObject *self, PyObject *args) {
int val;
if (!PyArg_ParseTuple(args, "i", &val))
val = SHTDN_REASON_MINOR_OTHER; // Provide failsafe
ExitWindowsEx(EWX_POWEROFF, val); // Shutdown
return Py_BuildValue("");
}
static PyObject * sys_restart(PyObject *self, PyObject *args) {
int val;
if (!PyArg_ParseTuple(args, "i", &val))
val = SHTDN_REASON_MINOR_OTHER; // Provide failsafe
ExitWindowsEx(EWX_REBOOT, val); // Restart
return Py_BuildValue("");
}
static PyObject * sys_log_out(PyObject *self, PyObject *args) {
int val;
if (!PyArg_ParseTuple(args, "i", &val))
val = SHTDN_REASON_MINOR_OTHER; // Provide failsafe
ExitWindowsEx(EWX_LOGOFF, val); // Log out
return Py_BuildValue("");
}
static PyMethodDef localMethods[] = {
{"shutdown", (PyCFunction)sys_shutdown, METH_VARARGS, "..."},
{"restart", (PyCFunction)sys_restart, METH_VARARGS, "..."},
{"log_out", (PyCFunction)sys_log_out, METH_VARARGS, "..."},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef func = {
PyModuleDef_HEAD_INIT,
"utilities",
"...",
-1,
localMethods,
};
PyMODINIT_FUNC PyInit_utilities(void) {
PyObject *value;
value = PyModule_New(&func);
PyModule_AddIntConstant(value, "DEFINED", AF_INET);
return PyModule_Create(&func);
}
Setup Script:
from distutils.core import setup, Extension
module = Extension(
"utilities",
sources = ["main.c"],
libraries = ["user32"]
)
setup (
name = "Utilities",
version = "1.0",
ext_modules = [module])
Everything builds as expected, however I cannot use DEFINED
in my extension:
import utilities
for i in utilities.__dict__: print(i)
utilities.DEFINED # AttributeError: module 'utilities' has no attribute 'DEFINED'
Returns:
__name__
__doc__
__package__
__loader__
__spec__
shutdown
restart
log_out
__file__
I thought of returning value
like so:
return PyModule_Create(&value);
But that returns:
LINK : fatal error LNK1104: cannot open file 'build\lib.win32-3.6\WinUtils.cp36-win32.pyd' error: command 'C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Tools\MSVC\14.14.26428\bin\HostX86\x86\link.exe' failed with exit status 1104
How can I add the DEFINED
value to my extension (so that I can run utilities.DEFINED
)?
Edit:
As mentioned in the answer below closing everything and trying again builds the extension successfully, however using return PyModule_Create(&value);
still crashes.
PyModule_AddIntConstant(value, "DEFINED", DEFINED_VALUE);
is correct (assuming that DEFINED_VALUE is a (C) long).
That, combined with the linker error at the end (and with the fact that you're writing code then testing, and so on ...) tells me that the linker is not able to write the new .pyd file (that contains the latest changes - including DEFINED variable), because it's in use by a previously started python.exe process that imported your module.
Close every running interpreter that imported your module (to "unlock" WinUtils.cp36-win32.pyd)
Build (this time, the linker will be able to overwrite the file)
Test (run your Python code)
Note: you could check the function return value ([Python.Docs]: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)).
As I specified in my one of my comments, use PyModule_Create (as according to [Python.Docs]: PyObject* PyModule_New(const char *name), you're getting Undefined Behavior):
PyMODINIT_FUNC PyInit_utilities()
{
PyObject *mod = PyModule_Create(&func);
PyModule_AddIntConstant(mod, "DEFINED", AF_INET);
return mod;
}