Hello all!

I had a question about how to handle void* and HWNDs from within Python
using Boost::Python and Py++. Reading through the Py++ documentation, I'm
loving how I can slice and dice my classes/wrappers and seemingly do
whatever I want with them, but there's still A LOT I haven't figured out.

I've found a previous set of similar questions here:
http://boost.2283326.n4.nabble.com/Wrapping-and-Passing-HWND-with-Boost-Python-td4598953.html
but didn't fully understand the automated implementation details.

All the relevant code is posted at the end, but my main questions were as
follows.

(1) Using the win32gui Python library, HWNDs are passed around as ints
describing the address of the window. These can be reinterpret_cast'ed into
HWNDs in C++ and that seems to work fine. However, using Py++, how can I
automatically inject a reinterpret_cast into Foo's constructor, or the
initializer list of a constructor wrapper? 

I've found these commands,
.add_declaration_code(...)
.add_registration_code(...)
.add_wrapper_code(...)
but they don't place code where I need it to go. 

So, is there a command that I should be using? My goal is to not touch my
Foo.hpp code (as in, no added code, no helper code), so I would like
everything to stay within the Boost::Python generated wrapper code
(FooWrapper.cpp).

(2) From Python, I would like to manipulate the memory of a buffer stored
within Foo. In my REAL code, the only accessor I can use is Address() which
returns a void pointer, which Py++/BP flips into an opaque pointer (which I
don't think I can use to manipulate m_buffer's memory in Python). 

One option is ctypes, but I frankly just don't know how to combine that with
BP for the purpose of manipulating data behind a void*, even after having
looked at the ctypes integration code in the Py++ docs.

The other option is to do something like what I did with the fake VoidPtr()
accessor. I could create accessors like VoidPtrAsUChar() for example, and
then expose those using the return_addressof call policy (hopefully!). If
this is, in fact, a valid approach, then I have the same question as
above... 

Given that I can't change the Foo.hpp code, is there a clean way of
injecting those AsUChar, AsInt, As... helper methods straight into the
wrapper code, so that they call Address() internally and then
reinterpret_cast the returned void* into something more useful and
accessible in Python?

Thanks!
-SJ

--------------------------------------------------
Here is my trivial Foo class:

#include <windows.h>
class Foo
{
public: 
    Foo( const HWND window )
        : m_wnd( window )
    {
        const unsigned int size = 10;
        m_buffer = new unsigned char[size];
        for( unsigned int i = 0; i < size; ++i )
            m_buffer[i] = i+1;
    }

    ~Foo()
    {   delete[] m_buffer;  }

    int IsWindow()
    {
        if ( ::IsWindow( m_wnd ) )
            return 1;
        return -1;
    }

    void* Address() // In my real code, this is the interface to access
memory
    { return reinterpret_cast< void* >( m_buffer ); }

    // Fake example accessors
    void* VoidPtr()
    { return reinterpret_cast< void* >( m_buffer ); }

    int* VoidPtrAsInt() 
    { return reinterpret_cast< int* >( m_buffer ); } 

    unsigned char* VoidPtrAsUChar() 
    { return reinterpret_cast< unsigned char* >( m_buffer ); } 

    char* VoidPtrAsChar() 
    { return reinterpret_cast< char* >( m_buffer ); } 

private:
    HWND m_wnd;
    unsigned char* m_buffer; // This buffer could be of any type in real
code

    Foo();
    Foo(const Foo&);
};

--------------------------------------------------
Here is my Py++ code:

mb = module_builder.module_builder_t(   files=fileList  
                                      , gccxml_path=pathToGccXml
                                      , working_directory=workingDirectory 
                                      , compiler='msvc9' )
                                      

mb.member_functions( return_type='char *' ).call_policies =
call_policies.return_value_policy( call_policies.return_addressof )
mb.member_functions( return_type='int *' ).call_policies =
call_policies.return_value_policy( call_policies.return_addressof )
mb.member_functions( return_type='unsigned char *' ).call_policies =
call_policies.return_value_policy( call_policies.return_addressof )

mb.build_code_creator( module_name='FooWrapper' )
FooWrapper = os.path.join( os.path.abspath('.'), 'FooWrapper.cpp' )

if os.path.exists( FooWrapper ):
    os.remove( FooWrapper )

mb.write_module( FooWrapper )

--------------------------------------------------
Which produces this generated code:
namespace bp = boost::python;

BOOST_PYTHON_MODULE(FooWrapper){
    { //::Foo
        typedef bp::class_< Foo, boost::noncopyable > Foo_exposer_t;
        Foo_exposer_t Foo_exposer = Foo_exposer_t( "Foo", bp::init< HWND__ *
>(( bp::arg("window") )) );
        bp::scope Foo_scope( Foo_exposer );
        bp::implicitly_convertible< HWND const, Foo >();
        { //::Foo::Address
        
            typedef void * ( ::Foo::*Address_function_type )(  ) ;
            
            Foo_exposer.def( 
                "Address"
                , Address_function_type( &::Foo::Address )
                , bp::return_value_policy< bp::return_opaque_pointer >() );
        
        }
        { //::Foo::IsWindow
        
            typedef int ( ::Foo::*IsWindow_function_type )(  ) ;
            
            Foo_exposer.def( 
                "IsWindow"
                , IsWindow_function_type( &::Foo::IsWindow ) );
        
        }
        { //::Foo::VoidPtr
        
            typedef void * ( ::Foo::*VoidPtr_function_type )(  ) ;
            
            Foo_exposer.def( 
                "VoidPtr"
                , VoidPtr_function_type( &::Foo::VoidPtr )
                , bp::return_value_policy< bp::return_opaque_pointer >() );
        
        }
        { //::Foo::VoidPtrAsChar
        
            typedef char * ( ::Foo::*VoidPtrAsChar_function_type )(  ) ;
            
            Foo_exposer.def( 
                "VoidPtrAsChar"
                , VoidPtrAsChar_function_type( &::Foo::VoidPtrAsChar )
                , bp::return_value_policy<
pyplusplus::call_policies::return_addressof >() );
        
        }
        { //::Foo::VoidPtrAsInt
        
            typedef int * ( ::Foo::*VoidPtrAsInt_function_type )(  ) ;
            
            Foo_exposer.def( 
                "VoidPtrAsInt"
                , VoidPtrAsInt_function_type( &::Foo::VoidPtrAsInt )
                , bp::return_value_policy<
pyplusplus::call_policies::return_addressof >() );
        
        }
        { //::Foo::VoidPtrAsUChar
        
            typedef unsigned char * ( ::Foo::*VoidPtrAsUChar_function_type
)(  ) ;
            
            Foo_exposer.def( 
                "VoidPtrAsUChar"
                , VoidPtrAsUChar_function_type( &::Foo::VoidPtrAsUChar )
                , bp::return_value_policy<
pyplusplus::call_policies::return_addressof >() );
        
        }
    }
}

--
View this message in context: 
http://boost.2283326.n4.nabble.com/Injecting-void-and-HWND-handling-code-from-Py-tp4630570.html
Sent from the Python - c++-sig mailing list archive at Nabble.com.
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to