A little black magic... When the C++ object (for a window or

whatever) is deleted there is no way to force the Python shadow object
to also be destroyed and clean up all references to it.  This leads to
crashes if the shadow object tries to call a method with the old C++
pointer...  The black magic I've done is to replace the __class__ in the
Python instanc object with a class that raises an exception whenever a
method call is attempted.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15059 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2002-04-09 22:01:45 +00:00
parent 31fa82942c
commit 4acff284f9
18 changed files with 207 additions and 84 deletions

View File

@@ -295,6 +295,7 @@ void __wxCleanup() {
static PyObject* wxPython_dict = NULL;
static PyObject* wxPyPtrTypeMap = NULL;
PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
{
@@ -334,6 +335,52 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
return Py_None;
}
//---------------------------------------------------------------------------
void wxPyClientData_dtor(wxPyClientData* self) {
wxPyBeginBlockThreads();
Py_DECREF(self->m_obj);
wxPyEndBlockThreads();
}
void wxPyUserData_dtor(wxPyUserData* self) {
wxPyBeginBlockThreads();
Py_DECREF(self->m_obj);
wxPyEndBlockThreads();
}
// This is called when an OOR controled object is being destroyed. Although
// the C++ object is going away there is no way to force the Python object
// (and all references to it) to die too. This causes problems (crashes) in
// wxPython when a python shadow object attempts to call a C++ method using
// the now bogus pointer... So to try and prevent this we'll do a little black
// magic and change the class of the python instance to a class that will
// raise an exception for any attempt to call methods with it. See
// _wxPyDeadObject in _extras.py for the implementation of this class.
void wxPyOORClientData_dtor(wxPyOORClientData* self) {
static PyObject* deadObjectClass = NULL;
wxPyBeginBlockThreads();
if (deadObjectClass == NULL) {
deadObjectClass = PyDict_GetItemString(wxPython_dict, "_wxPyDeadObject");
wxASSERT_MSG(deadObjectClass != NULL, wxT("Can't get _wxPyDeadObject class!"));
Py_INCREF(deadObjectClass);
}
// Clear the instance's dictionary, put the name of the old class into the
// instance, and then reset the class to be the dead class.
if (self->m_obj->ob_refcnt > 1) { // but only if there is more than one reference
wxASSERT_MSG(PyInstance_Check(self->m_obj), wxT("m_obj not an instance!?!?!"));
PyInstanceObject* inst = (PyInstanceObject*)self->m_obj;
PyDict_Clear(inst->in_dict);
PyDict_SetItemString(inst->in_dict, "_name", inst->in_class->cl_name);
inst->in_class = (PyClassObject*)deadObjectClass;
Py_INCREF(deadObjectClass);
}
wxPyEndBlockThreads();
}
//---------------------------------------------------------------------------
// Stuff used by OOR to find the right wxPython class type to return and to
@@ -344,6 +391,7 @@ PyObject* __wxSetDictionary(PyObject* /* self */, PyObject* args)
// is not the same as the shadow class name, for example wxPyTreeCtrl
// vs. wxTreeCtrl. It needs to be referenced in Python as well as from C++,
// so we'll just make it a Python dictionary in the wx module's namespace.
// (See __wxSetDictionary)
void wxPyPtrTypeMap_Add(const char* commonName, const char* ptrName) {
if (! wxPyPtrTypeMap)
wxPyPtrTypeMap = PyDict_New();
@@ -379,7 +427,7 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) {
isEvtHandler = TRUE;
wxEvtHandler* eh = (wxEvtHandler*)source;
wxPyClientData* data = (wxPyClientData*)eh->GetClientObject();
wxPyOORClientData* data = (wxPyOORClientData*)eh->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
@@ -400,9 +448,9 @@ PyObject* wxPyMake_wxObject(wxObject* source, bool checkEvtHandler) {
if (info) {
target = wxPyConstructObject(source, name, klass, FALSE);
if (target && isEvtHandler)
((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
((wxEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target));
} else {
wxString msg("wxPython class not found for ");
wxString msg(wxT("wxPython class not found for "));
msg += source->GetClassInfo()->GetClassName();
PyErr_SetString(PyExc_NameError, msg.mbc_str());
target = NULL;
@@ -423,7 +471,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) {
// already be a pointer to a Python object that we can use
// in the OOR data.
wxSizer* sz = (wxSizer*)source;
wxPyClientData* data = (wxPyClientData*)sz->GetClientObject();
wxPyOORClientData* data = (wxPyOORClientData*)sz->GetClientObject();
if (data) {
target = data->m_obj;
Py_INCREF(target);
@@ -432,7 +480,7 @@ PyObject* wxPyMake_wxSizer(wxSizer* source) {
if (! target) {
target = wxPyMake_wxObject(source, FALSE);
if (target != Py_None)
((wxSizer*)source)->SetClientObject(new wxPyClientData(target));
((wxSizer*)source)->SetClientObject(new wxPyOORClientData(target));
}
return target;
}