Martin
Martin

Reputation: 63

using ctypes to call a function pointer that points to a function that is defined static

I am using Python 3.6.0 and ctypes to access functions exported from a .dll. I want to access the functions by instantiating function prototype with a paramflags parameter. One of the functions in the .dll is defined static so it is not exported. However the .dll also contains a function pointer that points to that function and that is exported.

This is a simplified version of the .dll

typedef void ( *function ) ( int *output, int input );

__declspec( dllexport ) void two( int *output, int input );

__declspec( dllexport ) extern const function four;

void two( int *output, int input ) {
    *output =  2 * input;
}

static void three( int *output, int input ) {
    *output =  3 * input;
}

const function four = three;

and this is my Python code

import ctypes

dll = ctypes.cdll.test

# calling two( ) as an attribute of dll
two = dll.two
two.argtypes = [ ctypes.POINTER( ctypes.c_int ), ctypes.c_int ]
two.restype = None
output = ctypes.c_int( )
# output = c_long(2)
two( ctypes.byref( output ), 1 )
print( 'output =', output )

# calling two( ) by instantiating a function prototype with paramflags
function = ctypes.CFUNCTYPE( None, ctypes.POINTER( ctypes.c_int ), ctypes.c_int )
paramflags = ( ( 2, 'output' ), ( 1, 'input' ) )
two = function( ( 'two', dll ), paramflags )
# output = 2
output = two( 1 )
print( 'output =', output )

# I can call four( ) using in_dll( )
four = function.in_dll( dll, 'four' )
output = ctypes.c_int( )
# output = c_long(3)
four( ctypes.byref( output ), 1 )
print( 'output =', output )

# but not as an attribute of dll
four = dll.four
four.argtypes = [ ctypes.POINTER( ctypes.c_int ), ctypes.c_int ]
four.restype = None
output = ctypes.c_int( )
# this results in a "OSError: exception: access violation writing 0x6C0C3064"
four( ctypes.byref( output ), 1 )
print( 'output =', output )

# nor by instantiating a function prototype
paramflags = ( ( 2, 'output' ), ( 1, 'input' ) )
four = function( ( 'four', dll ), paramflags )
# this results in a "OSError: exception: access violation writing 0x6C0C3064"
output = four( 1 )
print( 'output =', output )

I can access two( ) as an attribute of dll, and by instantiating a function prototype. However when I try to do that with four( ) I get "OSError: exception: access violation writing 0x6C0C3064". After a lot of experimenting I found out that I can access four( ) using in_dll( ), but then I can't apply the paramflags functionality.

Is there any way to access four( ) and use paramflags?

Note: I don't want to change the dll (it's not part of my project) and am trying to solve it on the Python side.

Upvotes: 4

Views: 1719

Answers (2)

Mark Tolonen
Mark Tolonen

Reputation: 177725

I played with this awhile but since the way to instantiate a function with paramflags requires an exported function name and DLL in the syntax, it doesn't account for exported global function pointers.

Of course, you can get the same behavior with a little work by defining a wrapper to allocate and return the output parameter:

_four = function.in_dll( dll, 'four' )
def four(input):
    output = ctypes.c_int()
    _four(output,input)
    return output.value
output = four(5)
print('output =',output)

Upvotes: 1

Alex
Alex

Reputation: 779

"I am using Python 3.6.0 and ctypes to access functions exported from a .dll." I Think the problem is the following.

This

typedef void ( *function ) ( int *output, int input );
__declspec( dllexport ) extern const function four;

doesn't actually export a function from the dll, but only a pointer to a typedef'ed function, that is declared extern. In the end the Symbol Exporter has nothing really to work with. If you look for example in the generated lib after the build, you find a clean refenrence to two, but four is messed up.

If you declare the four function regulary

__declspec( dllexport ) const void four( int *output, int input );

and then define the function regulary

const void four( int *output, int input ) {
    *output =  3 * input;
}

then you should be able to access four() and use paramflags.

Upvotes: 0

Related Questions