From 4acff284f9516e2a4f0fcfa7bcfa3f497b8005cc Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Tue, 9 Apr 2002 22:01:45 +0000 Subject: [PATCH] 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 --- wxPython/contrib/ogl/ogl.cpp | 4 +- wxPython/contrib/ogl/ogl.i | 4 +- wxPython/contrib/ogl/oglbasic.cpp | 2 +- wxPython/contrib/ogl/oglbasic.i | 2 +- wxPython/src/_extras.py | 28 ++++++- wxPython/src/export.h | 3 + wxPython/src/helpers.cpp | 58 ++++++++++++-- wxPython/src/helpers.h | 128 ++++++++++++++++++------------ wxPython/src/msw/gdi.py | 4 +- wxPython/src/msw/sizers.cpp | 2 +- wxPython/src/msw/utils.cpp | 5 +- wxPython/src/msw/windows.cpp | 2 +- wxPython/src/msw/wx.cpp | 6 +- wxPython/src/msw/wx.py | 28 ++++++- wxPython/src/sizers.i | 2 +- wxPython/src/utils.i | 5 +- wxPython/src/windows.i | 2 +- wxPython/src/wx.i | 6 +- 18 files changed, 207 insertions(+), 84 deletions(-) diff --git a/wxPython/contrib/ogl/ogl.cpp b/wxPython/contrib/ogl/ogl.cpp index 9de0ddb93f..3c74a41f61 100644 --- a/wxPython/contrib/ogl/ogl.cpp +++ b/wxPython/contrib/ogl/ogl.cpp @@ -172,7 +172,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { // already be a pointer to a Python object that we can use // in the OOR data. wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source; - wxPyClientData* data = (wxPyClientData*)seh->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -181,7 +181,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { if (! target) { target = wxPyMake_wxObject2(source, FALSE); if (target != Py_None) - ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } return target; } diff --git a/wxPython/contrib/ogl/ogl.i b/wxPython/contrib/ogl/ogl.i index bdae01992f..dfa1a664a2 100644 --- a/wxPython/contrib/ogl/ogl.i +++ b/wxPython/contrib/ogl/ogl.i @@ -221,7 +221,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { // already be a pointer to a Python object that we can use // in the OOR data. wxShapeEvtHandler* seh = (wxShapeEvtHandler*)source; - wxPyClientData* data = (wxPyClientData*)seh->GetClientObject(); + wxPyOORClientData* data = (wxPyOORClientData*)seh->GetClientObject(); if (data) { target = data->m_obj; Py_INCREF(target); @@ -230,7 +230,7 @@ PyObject* wxPyMake_wxShapeEvtHandler(wxShapeEvtHandler* source) { if (! target) { target = wxPyMake_wxObject2(source, FALSE); if (target != Py_None) - ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyClientData(target)); + ((wxShapeEvtHandler*)source)->SetClientObject(new wxPyOORClientData(target)); } return target; } diff --git a/wxPython/contrib/ogl/oglbasic.cpp b/wxPython/contrib/ogl/oglbasic.cpp index 482538b0b2..c0bc910213 100644 --- a/wxPython/contrib/ogl/oglbasic.cpp +++ b/wxPython/contrib/ogl/oglbasic.cpp @@ -1249,7 +1249,7 @@ static PyObject *_wrap_wxPyShapeEvtHandler_Destroy(PyObject *self, PyObject *arg } static void wxPyShapeEvtHandler__setOORInfo(wxPyShapeEvtHandler *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxPyShapeEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/contrib/ogl/oglbasic.i b/wxPython/contrib/ogl/oglbasic.i index c1f6c83014..2338089016 100644 --- a/wxPython/contrib/ogl/oglbasic.i +++ b/wxPython/contrib/ogl/oglbasic.i @@ -99,7 +99,7 @@ public: %addmethods { void Destroy() { delete self; } } %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } diff --git a/wxPython/src/_extras.py b/wxPython/src/_extras.py index 708d1fd586..866ab98cf7 100644 --- a/wxPython/src/_extras.py +++ b/wxPython/src/_extras.py @@ -647,6 +647,26 @@ def wxPyTypeCast(obj, typeStr): return theObj +#---------------------------------------------------------------------------- + + +class _wxPyDeadObject: + """ + Instances of wx objects that are OOR capable will have their __class__ + changed to this class when the C++ object is deleted. This should help + prevent crashes due to referencing a bogus C++ pointer. + """ + def __repr__( self ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name + + def __getattr__( self, *args ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name + + #---------------------------------------------------------------------- #---------------------------------------------------------------------- @@ -763,10 +783,10 @@ class wxPyWidgetTester(wxApp): self.frame.Show(true) #---------------------------------------------------------------------------- -# DO NOT hold any other references to this object. This is how we know when -# to cleanup system resources that wxWin is holding. When this module is -# unloaded, the refcount on __cleanMeUp goes to zero and it calls the -# wxApp_CleanUp function. +# DO NOT hold any other references to this object. This is how we +# know when to cleanup system resources that wxWin is holding. When +# the sys module is unloaded, the refcount on sys.__wxPythonCleanup +# goes to zero and it calls the wxApp_CleanUp function. class __wxPyCleanup: def __init__(self): diff --git a/wxPython/src/export.h b/wxPython/src/export.h index c0b9c25a67..a38a1c7a67 100644 --- a/wxPython/src/export.h +++ b/wxPython/src/export.h @@ -74,6 +74,9 @@ static void wxPyCoreAPI_IMPORT() { #define wxArrayString2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayString2PyList_helper(a)) #define wxArrayInt2PyList_helper(a) (wxPyCoreAPIPtr->p_wxArrayInt2PyList_helper(a)) +#define wxPyClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyClientData_dtor(a)) +#define wxPyUserData_dtor(a) (wxPyCoreAPIPtr->p_wxPyUserData_dtor(a)) +#define wxPyOORClientData_dtor(a) (wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(a)) // This one is special. It's the first function called in SWIG generated // modules, so we'll use it to also import the API. diff --git a/wxPython/src/helpers.cpp b/wxPython/src/helpers.cpp index aa48fa7128..c3c52d2a6e 100644 --- a/wxPython/src/helpers.cpp +++ b/wxPython/src/helpers.cpp @@ -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; } diff --git a/wxPython/src/helpers.h b/wxPython/src/helpers.h index 50ba510883..4ec75ec534 100644 --- a/wxPython/src/helpers.h +++ b/wxPython/src/helpers.h @@ -101,6 +101,9 @@ bool wxRealPoint_helper(PyObject* source, wxRealPoint** obj); bool wxRect_helper(PyObject* source, wxRect** obj); bool wxColour_helper(PyObject* source, wxColour** obj); +//---------------------------------------------------------------------- +// Other helpful stuff + #if PYTHON_API_VERSION < 1009 #define PySequence_Fast_GET_ITEM(o, i) \ (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) @@ -113,9 +116,9 @@ bool _4int_seq_helper(PyObject* source, int* i1, int* i2, int* i3, int* i4); PyObject* wxArrayString2PyList_helper(const wxArrayString& arr); PyObject* wxArrayInt2PyList_helper(const wxArrayInt& arr); - -#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; } -#define DECLARE_DEF_STRING(name) static wxString wxPy##name(wx##name) +#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; } +#define DECLARE_DEF_STRING(name) static const wxString wxPy##name(wx##name) +#define DECLARE_DEF_STRING2(name,val) static const wxString wxPy##name(val) //---------------------------------------------------------------------- @@ -201,6 +204,18 @@ public: }; + +//---------------------------------------------------------------------- +// Forward decalre a few things used in the exported API +class wxPyClientData; +class wxPyUserData; +class wxPyOORClientData; + +void wxPyClientData_dtor(wxPyClientData* self); +void wxPyUserData_dtor(wxPyUserData* self); +void wxPyOORClientData_dtor(wxPyOORClientData* self); + + //--------------------------------------------------------------------------- // Export a C API in a struct. Other modules will be able to load this from // the wxc module and will then have safe access to these functions, even if @@ -256,11 +271,69 @@ struct wxPyCoreAPI { void (*p_wxPyPtrTypeMap_Add)(const char* commonName, const char* ptrName); PyObject* (*p_wxArrayString2PyList_helper)(const wxArrayString& arr); PyObject* (*p_wxArrayInt2PyList_helper)(const wxArrayInt& arr); + + void (*p_wxPyClientData_dtor)(wxPyClientData*); + void (*p_wxPyUserData_dtor)(wxPyUserData*); + void (*p_wxPyOORClientData_dtor)(wxPyOORClientData*); +}; + +#ifdef wxPyUSE_EXPORT +static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but doesn't have to use it. +#endif + + +//--------------------------------------------------------------------------- + + +class wxPyUserData : public wxObject { +public: + wxPyUserData(PyObject* obj) { + m_obj = obj; + Py_INCREF(m_obj); + } + + ~wxPyUserData() { +#ifdef wxPyUSE_EXPORT + wxPyCoreAPIPtr->p_wxPyUserData_dtor(this); +#else + wxPyUserData_dtor(this); +#endif + } + PyObject* m_obj; +}; + + +class wxPyClientData : public wxClientData { +public: + wxPyClientData(PyObject* obj) { + m_obj = obj; + Py_INCREF(m_obj); + } + + ~wxPyClientData() { +#ifdef wxPyUSE_EXPORT + wxPyCoreAPIPtr->p_wxPyClientData_dtor(this); +#else + wxPyClientData_dtor(this); +#endif + } + PyObject* m_obj; }; + +class wxPyOORClientData : public wxPyClientData { +public: + wxPyOORClientData(PyObject* obj) + : wxPyClientData(obj) {} + + ~wxPyOORClientData() { #ifdef wxPyUSE_EXPORT -static wxPyCoreAPI* wxPyCoreAPIPtr = NULL; // Each module needs one, but may not use it. + wxPyCoreAPIPtr->p_wxPyOORClientData_dtor(this); +#else + wxPyOORClientData_dtor(this); #endif + } +}; //--------------------------------------------------------------------------- // This class holds an instance of a Python Shadow Class object and assists @@ -312,53 +385,6 @@ void wxPyCBH_delete(wxPyCallbackHelper* cbh); -//---------------------------------------------------------------------- - -class wxPyUserData : public wxObject { -public: - wxPyUserData(PyObject* obj) { - m_obj = obj; - Py_INCREF(m_obj); - } - - ~wxPyUserData() { -#ifdef wxPyUSE_EXPORT - wxPyCoreAPIPtr->p_wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyCoreAPIPtr->p_wxPyEndBlockThreads(); -#else - wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyEndBlockThreads(); -#endif - } - PyObject* m_obj; -}; - - - -class wxPyClientData : public wxClientData { -public: - wxPyClientData(PyObject* obj) { - m_obj = obj; - Py_INCREF(m_obj); - } - - ~wxPyClientData() { -#ifdef wxPyUSE_EXPORT - wxPyCoreAPIPtr->p_wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyCoreAPIPtr->p_wxPyEndBlockThreads(); -#else - wxPyBeginBlockThreads(); - Py_DECREF(m_obj); - wxPyEndBlockThreads(); -#endif - } - PyObject* m_obj; -}; - - //--------------------------------------------------------------------------- // These macros are used to implement the virtual methods that should diff --git a/wxPython/src/msw/gdi.py b/wxPython/src/msw/gdi.py index eda13bc5ec..9ab2cec48f 100644 --- a/wxPython/src/msw/gdi.py +++ b/wxPython/src/msw/gdi.py @@ -866,14 +866,14 @@ class wxBufferedDC(wxBufferedDCPtr): def __init__(self,*_args,**_kwargs): self.this = apply(gdic.new_wxBufferedDC,_args,_kwargs) self.thisown = 1 - self._dc = _args[0] # save a ref so it won't be deleted before self + self._dc = _args[0] # save a ref so the other dc won't be deleted before self def wxBufferedDCInternalBuffer(*_args,**_kwargs): val = wxBufferedDCPtr(apply(gdic.new_wxBufferedDCInternalBuffer,_args,_kwargs)) val.thisown = 1 - val._dc = _args[0] # save a ref so it won't be deleted before self + val._dc = _args[0] # save a ref so the other dc won't be deleted before self return val diff --git a/wxPython/src/msw/sizers.cpp b/wxPython/src/msw/sizers.cpp index 5bddf40caf..bc740b04cf 100644 --- a/wxPython/src/msw/sizers.cpp +++ b/wxPython/src/msw/sizers.cpp @@ -860,7 +860,7 @@ static void *SwigwxSizerTowxObject(void *ptr) { } static void wxSizer__setOORInfo(wxSizer *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxSizer__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/src/msw/utils.cpp b/wxPython/src/msw/utils.cpp index 4475235a09..657cefed9c 100644 --- a/wxPython/src/msw/utils.cpp +++ b/wxPython/src/msw/utils.cpp @@ -55,14 +55,13 @@ extern PyObject *SWIG_newvarlink(void); #define SWIG_name "utilsc" -#include "export.h" +#include "helpers.h" #include #include #include // Put some wx default wxChar* values into wxStrings. - static const wxChar* wxDateFormatStr = wxT("sashWindow"); - DECLARE_DEF_STRING(DateFormatStr); + DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow")); static const wxString wxPyEmptyString(wxT("")); diff --git a/wxPython/src/msw/windows.cpp b/wxPython/src/msw/windows.cpp index 228779aa2b..93f30a99af 100644 --- a/wxPython/src/msw/windows.cpp +++ b/wxPython/src/msw/windows.cpp @@ -548,7 +548,7 @@ static PyObject *_wrap_wxEvtHandler_Disconnect(PyObject *self, PyObject *args, P } static void wxEvtHandler__setOORInfo(wxEvtHandler *self,PyObject * _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } static PyObject *_wrap_wxEvtHandler__setOORInfo(PyObject *self, PyObject *args, PyObject *kwargs) { PyObject * _resultobj; diff --git a/wxPython/src/msw/wx.cpp b/wxPython/src/msw/wx.cpp index fe8e6ac8c3..7d73f40df8 100644 --- a/wxPython/src/msw/wx.cpp +++ b/wxPython/src/msw/wx.cpp @@ -677,7 +677,11 @@ static wxPyCoreAPI API = { wxPyMake_wxSizer, wxPyPtrTypeMap_Add, wxArrayString2PyList_helper, - wxArrayInt2PyList_helper + wxArrayInt2PyList_helper, + + wxPyClientData_dtor, + wxPyUserData_dtor, + wxPyOORClientData_dtor }; diff --git a/wxPython/src/msw/wx.py b/wxPython/src/msw/wx.py index 2cc382ee35..35e1ba43d2 100644 --- a/wxPython/src/msw/wx.py +++ b/wxPython/src/msw/wx.py @@ -1554,6 +1554,26 @@ def wxPyTypeCast(obj, typeStr): return theObj +#---------------------------------------------------------------------------- + + +class _wxPyDeadObject: + """ + Instances of wx objects that are OOR capable will have their __class__ + changed to this class when the C++ object is deleted. This should help + prevent crashes due to referencing a bogus C++ pointer. + """ + def __repr__( self ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + return 'wxPython wrapper for deleted %s object!!! Programming logic error' % self._name + + def __getattr__( self, *args ): + if not hasattr(self, "_name"): + self._name = "[unknown]" + raise ValueError, 'Attempt to access attribute of a deleted %s object' % self._name + + #---------------------------------------------------------------------- #---------------------------------------------------------------------- @@ -1670,10 +1690,10 @@ class wxPyWidgetTester(wxApp): self.frame.Show(true) #---------------------------------------------------------------------------- -# DO NOT hold any other references to this object. This is how we know when -# to cleanup system resources that wxWin is holding. When this module is -# unloaded, the refcount on __cleanMeUp goes to zero and it calls the -# wxApp_CleanUp function. +# DO NOT hold any other references to this object. This is how we +# know when to cleanup system resources that wxWin is holding. When +# the sys module is unloaded, the refcount on sys.__wxPythonCleanup +# goes to zero and it calls the wxApp_CleanUp function. class __wxPyCleanup: def __init__(self): diff --git a/wxPython/src/sizers.i b/wxPython/src/sizers.i index a43993df98..1e65076ff9 100644 --- a/wxPython/src/sizers.i +++ b/wxPython/src/sizers.i @@ -97,7 +97,7 @@ public: %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } diff --git a/wxPython/src/utils.i b/wxPython/src/utils.i index ada7c8ad11..24a33a10ef 100644 --- a/wxPython/src/utils.i +++ b/wxPython/src/utils.i @@ -14,7 +14,7 @@ %module utils %{ -#include "export.h" +#include "helpers.h" #include #include #include @@ -23,8 +23,7 @@ //--------------------------------------------------------------------------- %{ // Put some wx default wxChar* values into wxStrings. - static const wxChar* wxDateFormatStr = wxT("sashWindow"); - DECLARE_DEF_STRING(DateFormatStr); + DECLARE_DEF_STRING2(DateFormatStr, wxT("sashWindow")); static const wxString wxPyEmptyString(wxT("")); %} diff --git a/wxPython/src/windows.i b/wxPython/src/windows.i index a79cea8664..10778765a6 100644 --- a/wxPython/src/windows.i +++ b/wxPython/src/windows.i @@ -87,7 +87,7 @@ public: %addmethods { void _setOORInfo(PyObject* _self) { - self->SetClientObject(new wxPyClientData(_self)); + self->SetClientObject(new wxPyOORClientData(_self)); } } }; diff --git a/wxPython/src/wx.i b/wxPython/src/wx.i index f51a623b6d..351c6e4bb1 100644 --- a/wxPython/src/wx.i +++ b/wxPython/src/wx.i @@ -202,7 +202,11 @@ static wxPyCoreAPI API = { wxPyMake_wxSizer, wxPyPtrTypeMap_Add, wxArrayString2PyList_helper, - wxArrayInt2PyList_helper + wxArrayInt2PyList_helper, + + wxPyClientData_dtor, + wxPyUserData_dtor, + wxPyOORClientData_dtor }; -- 2.45.2