Injecting void* and HWND handling code from Py++

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Injecting void* and HWND handling code from Py++

Suresh Joshi
This post has NOT been accepted by the mailing list yet.
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: 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,
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?


Here is my trivial Foo class:

#include <windows.h>
class Foo
    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;

    {   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 ); }

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

    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;

    { //::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 )(  ) ;
                , Address_function_type( &::Foo::Address )
                , bp::return_value_policy< bp::return_opaque_pointer >() );
        { //::Foo::IsWindow
            typedef int ( ::Foo::*IsWindow_function_type )(  ) ;
                , IsWindow_function_type( &::Foo::IsWindow ) );
        { //::Foo::VoidPtr
            typedef void * ( ::Foo::*VoidPtr_function_type )(  ) ;
                , VoidPtr_function_type( &::Foo::VoidPtr )
                , bp::return_value_policy< bp::return_opaque_pointer >() );
        { //::Foo::VoidPtrAsChar
            typedef char * ( ::Foo::*VoidPtrAsChar_function_type )(  ) ;
                , VoidPtrAsChar_function_type( &::Foo::VoidPtrAsChar )
                , bp::return_value_policy< pyplusplus::call_policies::return_addressof >() );
        { //::Foo::VoidPtrAsInt
            typedef int * ( ::Foo::*VoidPtrAsInt_function_type )(  ) ;
                , VoidPtrAsInt_function_type( &::Foo::VoidPtrAsInt )
                , bp::return_value_policy< pyplusplus::call_policies::return_addressof >() );
        { //::Foo::VoidPtrAsUChar
            typedef unsigned char * ( ::Foo::*VoidPtrAsUChar_function_type )(  ) ;
                , VoidPtrAsUChar_function_type( &::Foo::VoidPtrAsUChar )
                , bp::return_value_policy< pyplusplus::call_policies::return_addressof >() );