1

我正在尝试使用 Python 打开一个对话框以接受对我的 C++ 应用程序的输入。

这是我正在尝试做的一个非常小的表示:

#include <iostream>
#include <Python.h>

int main()
{
    /* Begin Python Ititialization - only needs to be done once. */
    PyObject *ip_module_name = NULL;
    PyObject *ip_module = NULL;
    PyObject *ip_module_contents = NULL;
    PyObject *ip_module_getip_func = NULL;

    Py_Initialize();
    PyEval_InitThreads();

    ip_module_name     = PyString_FromString( "get_ip" );
    ip_module          = PyImport_Import( ip_module_name );
    ip_module_contents = PyModule_GetDict( ip_module );
    ip_module_getip_func = PyDict_GetItemString( ip_module_contents, "get_ip_address" );
    /* End Initialization */

    PyGILState_STATE state = PyGILState_Ensure();
    PyObject *result = PyObject_CallObject( ip_module_getip_func, NULL );

    if( result == Py_None )
        printf( "None\n" );
    else
        printf( "%s\n", PyString_AsString( result ) );

    PyGILState_Release( state );

    /* This is called when the progam exits. */
    Py_Finalize();
}

但是,当我使用 PyObject_CallObject 调用该函数时,应用程序会出现段错误。我猜这是因为我使用的是 Tk 库。我尝试将我的应用程序与 _tkinter.lib、tk85.lib、tcl85.lib、tkstub85.lib、tclstub85.lib 链接,但这些都没有帮助。我好难过...

这是脚本:

import Tkinter as tk
from tkSimpleDialog import askstring
from tkMessageBox import showerror

def get_ip_address():

    root = tk.Tk()
    root.withdraw()

    ip = askstring( 'Server Address', 'Enter IP:' )

    if ip is None:
        return None

    ip = ip.strip()

    if ip is '':
        showerror( 'Error', 'Please enter a valid IP address' )
        return get_ip_address()

    if len(ip.split(".")) is not 4:
        showerror( 'Error', 'Please enter a valid IP address' )
        return get_ip_address()

    for octlet in ip.split("."):
        x = 0

        if octlet.isdigit():
            x = int(octlet)
        else:
            showerror( 'Error', 'Please enter a valid IP address' )
            return get_ip_address()

        if not ( x < 256 and x >= 0 ):
            showerror( 'Error', 'Please enter a valid IP address' )
            return get_ip_address()

    return ip

编辑:添加了我的线程设置

4

1 回答 1

3

添加PySys_SetArgv(argc, argv)(与int argc, char **argv参数一起main),您的代码将起作用。

tk.Tk()accesses ,除非被调用sys.argv,否则它不存在。PySys_SetArgv这会导致一个异常,该异常通过返回传播get_ip并报告给 Python/C 。被存储并传递给,这是观察到的崩溃的直接原因。PyObject_CallObjectNULLNULLresultPyString_AsString

对代码的几点说明:

  • 调试它花费了很多精力,因为代码不进行任何错误检查,它盲目地向前推进,直到由于传递 NULL 指针而崩溃。至少可以写如下内容:

    if (!ip_module_name) {
        PyErr_Print();
        exit(1);
    }
    // and so on for every PyObject* that you get from a Python API call
    

    在实际代码中,您不会exit(),但会进行一些清理并返回NULL(或引发 C++ 级异常,或任何适当的)。

  • 无需调用PyGILState_Ensure您已经知道持有 GIL 的线程。作为状态的文档PyEval_InitThreads,它初始化 GIL 并获取它。您只需要在从 C 回调调用 Python 时重新获取 GIL,该回调来自例如与 Python 无关的工具包事件循环。

  • 从 Python 收到的新引用Py_DECREF一旦不再需要就需要被 'ed 。为简洁起见,最小示例中可能会省略引用计数,但应始终注意它。

于 2013-04-25T17:06:42.840 回答