2

I am trying to access a C++ dll from python (I am new to Python). I overcame many calling convention issues and finally got it to run without any compile/linking error. However when I print the returning array from C++ dll in python it shows all random initialized values. It looks like the values were not correctly returned.

My C++ code looks like this.

double DLL_EXPORT __cdecl *function1(int arg1, int arg2, double arg3[],int arg4,double arg5,double arg6,double arg7, double arg8)
{     
        double *Areas = new double[7];

        ....Calculations

        return Areas;
}

My python code looks as follows:

import ctypes

CalcDll = ctypes.CDLL("CalcRoutines.dll")

arg3_py=(ctypes.c_double*15)(1.926,1.0383,0.00008,0.00102435,0.0101,0.0,0.002,0.0254,102,1,0.001046153,0.001046153,0.001046153,0.001046153,20)
dummy = ctypes.c_double(0.0)

CalcDll.function1.restype = ctypes.c_double*7
Areas = CalcDll.function1(ctypes.c_int(1),ctypes.c_int(6),arg3_py,ctypes.c_int(0),dummy,dummy,dummy,dummy)

for num in HxAreas:
    print("\t", num)

The output of the print statement is as below:

     2.4768722583947873e-306
     3.252195577561737e+202
     2.559357001198207e-306
     5e-324
     2.560791130833573e-306
     3e-323
     2.5621383435212475e-306

Any suggestion on what I am doing wrong is greatly appreciated.

J.J. Hakala
  • 6,136
  • 6
  • 27
  • 61
snkp
  • 43
  • 7
  • 1
    Note that functions returning structs do not always do this the same way for different compilers (I learnt this the hard way). The way your C++ compiler returns such structs may be incompatible with the way your version of Python expects. – Rudy Velthuis Jul 21 '16 at 20:44
  • http://stackoverflow.com/a/6731737/95954 – Rudy Velthuis Jul 21 '16 at 20:51
  • 2
    It is probably better to return an array of doubles that has been allocated with `malloc()` so it can be deallocated by ctypes. – J.J. Hakala Jul 21 '16 at 20:54
  • Also: http://stackoverflow.com/a/6726624/95954 – Rudy Velthuis Jul 21 '16 at 21:04
  • 1
    @J.J.Hakala: only if ctypes is able to use the identical memory manager. That is *very* unlikely when the C memory manager is in a DLL and ctypes is not. See the link in my third comment: pass an explicit poibter to a buffer allocated by the caller. The DLL only copies into the buffer. – Rudy Velthuis Jul 21 '16 at 21:09
  • Wish I could upvote the comment about having the caller provide the buffer more. I can't, so here's useless "Me too!" comment to emphasize how much this can simplify memory management. – user4581301 Jul 21 '16 at 21:12
  • FWIW, you iterate over HxAreas, but the function return is held in Areas. Is there some kind of aliasing between these, or is that simply a bug? I don't know enough of Python to tell which it is. – Rudy Velthuis Jul 21 '16 at 21:18
  • @RudyVelthuis That was just a typo. Sorry for the confusion – snkp Jul 22 '16 at 01:23
  • Typos shouldn't occur, because they can obfuscate the real problem. Always copy and paste your actual code, not something you typed into the message editor for this forum. – Rudy Velthuis Jul 22 '16 at 06:27
  • @Rudy Velthuis I understand and will keep that in mind. Thank you. – snkp Jul 22 '16 at 19:28

1 Answers1

2

Instead of

CalcDll.function1.restype = ctypes.c_double * 7

there should be

CalcDll.function1.restype = ctypes.POINTER(ctypes.c_double)

and then

Areas = CalcDll.function1(ctypes.c_int(1), ctypes.c_int(6), arg3_py,
                          ctypes.c_int(0), dummy, dummy, dummy, dummy)

for i in range(7):
    print("\t", Areas[i])

I'm not sure what ctypes does in case of 'ctypes.c_double * 7', if it tries to extract seven double from the stack or what.

Tested with

double * function1(int arg1, int arg2, double arg3[],
                   int arg4, double arg5, double arg6,
                   double arg7, double arg8)
{
    double * areas = malloc(sizeof(double) * 7);
    int i;

    for(i=0; i<7; i++) {
        areas[i] = i;
    }

    return areas;
}

the values in the array are printed correctly with restype = ctypes.POINTER(ctypes.c_double)

J.J. Hakala
  • 6,136
  • 6
  • 27
  • 61