/*---------------stdcallbk_module.h---------------------*/
#ifndef STDCALLBK_MODULE_H
#include <Python.h>
#define STDCALLBK_MODULE_H
// Type definition for the callback function.
typedef void __stdcall(CALLBK_FUNC_T)(const char* p);
#ifdef __cplusplus
extern "C" {
#endif
void register_callback(CALLBK_FUNC_T* callback);
void import_stdcallbk(void);
#ifdef __cplusplus
}
#endif
#endif /* #define STDCALLBK_MODULE_H */
/*---------------stdcallbk_module.c---------------------*/
#include "stdcallbk_module.h"
static CALLBK_FUNC_T *callback_write_func = NULL;
static FILE *fp; /*for debugging*/
static PyObject* g_stdout;
typedef struct
{
PyObject_HEAD
CALLBK_FUNC_T *write;
} Stdout;
static PyObject* write2(PyObject* self, PyObject* args)
{
const char* p;
if (!PyArg_ParseTuple(args, "s", &p))
return NULL;
fputs(p, fp); fflush(fp);
if(callback_write_func)
callback_write_func(p);
else
printf("----%s----", p);
return PyLong_FromLong(strlen(p));
}
static PyObject* flush2(PyObject* self, PyObject* args)
{
// no-op
return Py_BuildValue("");
}
static PyMethodDef Stdout_methods[] =
{
{"write", write2, METH_VARARGS, "sys-stdout-write"},
{"flush", flush2, METH_VARARGS, "sys-stdout-write"},
{NULL, NULL, 0, NULL}
};
static PyTypeObject StdoutType =
{
PyVarObject_HEAD_INIT(0, 0)
"stdcallbk.StdoutType", /* tp_name */
sizeof(Stdout), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"stdcallbk.Stdout objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Stdout_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
static struct PyModuleDef stdcallbkmodule = {
PyModuleDef_HEAD_INIT,
"stdcallbk", /* name of module */
NULL, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
NULL,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC PyInit_stdcallbk(void)
{
PyObject* m;
fp = fopen("debuggered.txt", "wt");
fputs("got to here Vers 12\n", fp); fflush(fp);
StdoutType.tp_new = PyType_GenericNew;
if (PyType_Ready(&StdoutType) < 0)
return 0;
m = PyModule_Create(&stdcallbkmodule);
if (m)
{
Py_INCREF(&StdoutType);
PyModule_AddObject(m, "Stdout", (PyObject*) &StdoutType);
fputs("PyModule_AddObject() Called\n", fp); fflush(fp);
}
g_stdout = StdoutType.tp_new(&StdoutType, 0, 0);
/*PySys_SetObject("stdout", g_stdout)*/
fprintf(fp, "PySys_SetObject(stdout) returned %d\n", PySys_SetObject("stdout", g_stdout));
fflush(fp);
/*PySys_SetObject("stderr", g_stdout)*/
fprintf(fp, "PySys_SetObject(stderr) returned %d\n", PySys_SetObject("stderr", g_stdout));
fflush(fp);
return m;
}
/* called by cpp exe _after_ Py_Initialize(); */
void __declspec(dllexport) import_stdcallbk(void)
{
PyImport_ImportModule("stdcallbk");
}
/* called by cpp exe _before_ Py_Initialize(); */
void __declspec(dllexport) register_callback(CALLBK_FUNC_T* callback)
{
PyImport_AppendInittab("stdcallbk", &PyInit_stdcallbk);
callback_write_func = callback;
}
/*------------- Embarcadero C++ Builder exe ---------------------*/
#include "/py_module/stdcallbk_module.h"
void __stdcall callback_write_func(const char* p)
{
ShowMessage(p);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
PyObject *pName, *pModule;
register_callback(callback_write_func);
Py_Initialize();
import_stdcallbk();
//PyRun_SimpleString("import stdcallbk\n");
pName = PyUnicode_FromString("hello_emb.py");
pModule = PyImport_Import(pName);
Py_Finalize();
}
//---------------------------------------------------------------------------
-------------- python script - hello_emb.py ----------------
#import stdcallbk
print("HELLO FRED !")
assert 1==2
------------------------------------------------------------
上面的代码是从这里借用的:How to redirect stderr in Python? 通过 Python C API?
从 cpp exe 运行时,我收到一个消息框“HELLO FRED!” 接下来是一个空的消息框,我认为它是回车。到目前为止一切都很好,但是当引发异常时,我什么也得不到。也没有将任何内容写入文本文件。
但是......如果我从python脚本中取消注释“import stdcallbk”并从命令行运行它,我会得到这个:
D:\projects\embed_python3\Win32\Debug>hello_emb.py
----HELLO FRED !--------
--------Traceback (most recent call last):
-------- File "D:\projects\embed_python3\Win32\Debug\hello_emb.py", line 7, in <module>
-------- --------assert 1==2--------
--------AssertionError----------------
----
和这个:
D:\projects\embed_python3\Win32\Debug>type debuggered.txt
got to here Vers 12
PyModule_AddObject() Called
PySys_SetObject(stdout) returned 0
PySys_SetObject(stderr) returned 0
HELLO FRED !
Traceback (most recent call last):
File "D:\projects\embed_python3\Win32\Debug\hello_emb.py", line 7, in <module>
assert 1==2
AssertionError
所以它确实有效,只是在从 cpp exe 运行时无效。
有人知道这里到底发生了什么吗?
干杯