
Thanks for the feedback! Yes I am glad someone is posting me message! :) Heres my full.cpp file that will hopefully shed some light on my Boost bumbling. Below that is my python script too. I was just typing the code snippets from memory and I noticed I misled on my virtual function return value. In fact, its a void return value. It does throw a runtime exception. Ive commented the line of code in main() where it throws the exception. Thanks for all the help! If I can get these passing C++ pointers to Python issues hammered out, Ill forever proclaim Boost's greatness, and Ill never look at Lua (or Perl) again ;) -Dave #include <windows.h> #include <iostream> #include <string> #include <cstdio> #include <conio.h> #undef _DEBUG // just forcing the non-debug library by doing this #include <Python.h> #define _DEBUG // just forcing the non-debug library by doing this #include <boost/python/class.hpp> #include <boost/python/def.hpp> #include <boost/python/str.hpp> #include <boost/python/extract.hpp> #include <boost/python/module.hpp> #include <boost/python/call_method.hpp> #include <boost/python/handle.hpp> #include <boost/python.hpp> using namespace boost::python; // Error codes #define Success 0 #define PY_InitError -100 #define PY_ConvertError -101 #define PY_CallError -102 // Global module pointer boost::python::handle<> my_module; //////////////////////////////////////////////////////////////////////////// ////////// //////////////////////////////////////////////////////////////////////////// ////////// class Base1 { public: int z; Base1() { z= 1; }; /* ** I dont want Python to even care about this function! My other C++ code classes may (or may not) ** override this function. No Python script should ever override this. The default behavior is ** to do nothing. I figured if I dont expose it to the BOOST_PYTHON_MODULE, why would it need ** to care about this function? Again, if I comment this out, everything works perfectly. Otherwise, ** I get a runtime exception about non_rtti_object. */ virtual void OnKeyUp(unsigned short virtual_key) { }; }; //////////////////////////////////////////////////////////////////////////// ////////// //////////////////////////////////////////////////////////////////////////// ////////// class TestC : public Base1 { protected: int x; public: TestC() { x = 0; }; void Set(int val) { x = val; }; int Get(void) { return x; }; void printPtr() { printf("C++ : Ptr=0x%p", this); } }; //////////////////////////////////////////////////////////////////////////// ////////// // Python wrapper for TestC //////////////////////////////////////////////////////////////////////////// ////////// BOOST_PYTHON_MODULE(grumsh) { using namespace boost::python; object testClass = class_<TestC, boost::shared_ptr<TestC> >( "TestC", init<>()) .def("Get", &TestC::Get) .def("Set", &TestC::Set) .def("printPtr", &TestC::printPtr) ; } /* grumsh */ //////////////////////////////////////////////////////////////////////////// ////////// // Function prototypes //////////////////////////////////////////////////////////////////////////// ////////// int initPython(std::string scriptName); int callPython(std::string func, std::string msg, boost::python::object& obj); //////////////////////////////////////////////////////////////////////////// ////////// // Convenience functions //////////////////////////////////////////////////////////////////////////// ////////// boost::python::handle<> import_module(std::string module_name) { using namespace boost::python; PyObject *module_ptr = PyImport_ImportModule(const_cast<char*>(module_name.c_str())); if (module_ptr == NULL) { OutputDebugString("import_module, NULL\n"); exit(1); } return handle<>(module_ptr); } /* import_module */ //////////////////////////////////////////////////////////////////////////// ////////// //////////////////////////////////////////////////////////////////////////// ////////// boost::python::object get_function(const char * func_name) { // Borrowed reference PyObject * dict = PyModule_GetDict(my_module.get()); boost::python::str funcName(func_name); return boost::python::object(boost::python::handle<>(PyDict_GetItem(dict, funcName.ptr()))); } /* get_function */ //////////////////////////////////////////////////////////////////////////// ////////// // Call a function in module (ptrPyModule) with two arguments // func: Name of python function // msg: Message string // obj: Boost.Python object (an instance of a wrapped class) //////////////////////////////////////////////////////////////////////////// ////////// int callPython(const std::string funcStr, std::string msg, boost::python::object& obj) { int rval; boost::python::object func = get_function(const_cast<char*>(funcStr.c_str())); rval = boost::python::extract<int>(func(msg, obj)); return rval; } /* callPython */ //////////////////////////////////////////////////////////////////////////// ////////// // Initialize Python interpreter // Initialize Extension module that expose C++ classes/objects to Python script // Set up sys.path to include script path (Where the python scripts can be found) //////////////////////////////////////////////////////////////////////////// ////////// int initPython(std::string scriptName) { if(scriptName.length() == 0) return PY_InitError; // Register the extension module PyImport_AppendInittab("grumsh", initgrumsh); // Initialize the Python interpreter Py_Initialize(); PySys_SetPath(strcat(Py_GetPath(), ";.\\scripts\\;\\code\\cpp\\python\\scripts\\")); char * oldpath = Py_GetPath(); // Import the module, storing the pointer in a handle<> my_module = import_module(const_cast<char*>(scriptName.c_str())); return Success; } int main() { int rval; /* Create a new Test class instance. */ TestC * test = new TestC(); /* ** Try any way to wrap it such that I can pass a pointer to my Python script so it can call ** my exposed member functions. */ boost::shared_ptr<TestC> test1ptr(test); std::cout << "C++ : Initializing Python and loading script" << std::endl; int retv = initPython("test_script"); if( retv == Success ) { test1ptr->printPtr(); std::cout << std::endl; std::cout << "C++ : test1ptr->Get() in C++ before Python call: " << test1ptr->Get() << std::endl; /* ** This is where I get a RUNTIME exception (non_rtti_object). If I comment out the virtual ** member function out of the class Base1, this works perfectly! */ object arg2(test1ptr); /* This works great too as long as I dont have the virtual member function. */ int retv = callPython("myTestFunc", "Test String argument from c++", arg2); std::cout << "C++ : callPython() returned: " << retv << std::endl; std::cout << "C++ : test1ptr->Get() after Python call: " << test1ptr->Get() << std::endl; std::cout << "C++ : Press any key to quit" << std::endl; getch(); } return 0; } /* main */ Ok, and heres the full test_script.py file: ========================== try: import grumsh print "Python: Import SUCCEEDED!!!" except: print "Python: Import FAILED..." ############################################################################ ######### ############################################################################ ######### def my_test(ptr): return 0; ############################################################################ ######### # Test module # Illustrate both instatiation and use of already instantiated C++ objects ############################################################################ ######### def myTestFunc(msg, cppObj): # Print message from C++ print "Python: msg = ", msg # Instantiate a MyClass object a = grumsh.TestC() # Show identity print "Python: Identity of 'local' MyClass object: ", a.printPtr() print # Change state of object print "Python: Current state:", a.Get() a.Set(1234) print "Python: New state :", a.Get() # Delete object del a # Test the object exposed from c++ (Passed as a formal parameter) # Show identify of cppObj print "Python: Identity of exposed cppObj: ", cppObj.printPtr() print # Show state of cppObj print "Python: cppObj.Get() on entry:", cppObj.Get() # Change state of object cppObj.Set(9) # Show state of object print "Python: cppObj.Get() on exit :", cppObj.Get() return 999