0

According to this question: Read char16_t* String with cppyy from c++ I have a new problem with the char16_t* in a user defined struct.

Given a C++ function:

MLPI_API MLPIRESULT mlpiMotionGetConfiguredAxes(const MLPIHANDLE connection, MlpiAxisInformation* configAxes, const ULONG numElements, ULONG *numElementsRet);

typedef unsigned int                  ULONG;
typedef char16_t                    WCHAR16;
typedef struct MlpiAxisInformation
{
  MlpiAxisRef     axis;                                 //!< Logical axis address.
  ULONG           deviceAddress;                        //!< (SERCOS) device address.
  MlpiAxisType    axisType;                             //!< Type of axis (virtual, real, etc...).
  WCHAR16         name[MLPI_MOTION_MAX_AXIS_NAME_LEN];  //!< The axis name.
}MlpiAxisInformation;

For ctypes I defined the structures as classes and built an array from it. But then the string does not work. Cppyy is able to handle the sting, but I have no clue how to hand over the array and wrap the string then..

(Working) Vanilla ctypes-code:

class MlpiAxisRef(ctypes.Structure):
    _fields_ = [
        ("controlNo",ctypes.c_int),
        ("axisNo",ctypes.c_int)]


class MlpiAxisInformation(ctypes.Structure):
    _fields_ = [
        ("axis", MlpiAxisRef),
        ("deviceAddress",ctypes.c_ulong),
        ("axisType", ctypes.c_int),
        ("name", ctypes.c_wchar*100)
        ]

def MLPIGetConfiguredAxes(self) -> List[MlpiAxisInformation]:
        length = ctypes.c_ulong(99)
        length_ret = ctypes.c_ulong(0)

        self._mlpi.mlpiMotionGetConfiguredAxes.argtypes = (ctypes.c_ulonglong, ctypes.POINTER(MlpiAxisInformation), ctypes.c_ulong, ctypes.POINTER(ctypes.c_ulong))
        self._mlpi.mlpiMotionGetConfiguredAxes.restype = ctypes.c_long
        val = (MlpiAxisInformation*100)()
        ret = self._mlpi.mlpiMotionGetConfiguredAxes(self.con, val, length, length_ret)

How to get back the MlpiAxisInformation-Array with working strings?

cppyy = "==1.7.0" due to problems in dockerize later versions..

araisch
  • 1,727
  • 4
  • 15
  • (Aside: what are the dockerize problems? 2.0.0 brings in the newer Clang9, so that's quite an upgrade.) Otherwise, I'm trying to figure out what exactly you are asking, as there isn't a runnable example AFACIT? The fixed-size array of `char16_t` is treated as an array, not as a string by cppyy. Is the question how to turn such an array into a unicode Python `str`? – Wim Lavrijsen Aug 10 '21 at 18:28
  • Hi Wim, no there is no runnable example, because it is taking to a hardware device. And I have no access to the code of the library (just headers), so I can't code a simulator. The problem for char16_t you solved perfectly in the linked question, but I don't know how to solve that for an array of custom structures as pointer argument. The dockerize problem was prior to 2.0.0, maybe I will retry. I will report later. – araisch Aug 11 '21 at 06:52

1 Answers1

0

Although I'm still unclear about the actual intend here, esp. since there is no runnable example, I'm guessing that the gist of it is that the array type is treated as "data" rather than as a "string" and you want this interpretation reversed.

Let's start with something runnable:

import cppyy

cppyy.cppdef(r"""\
  struct AxisInformation {
  AxisInformation() : name{u'h', u'e', u'l', u'l', u'o', u'\0'} {}
  char16_t name[16];
};""")

ai = cppyy.gbl.AxisInformation()

At this point, ai.name is an array type, so e.g. print(ai.name) will yield <cppyy.LowLevelView object at 0x7fe1eb0b31b0>. Now, to treat the char16_t[] as a string instead, it should have been a char16_t. One way to get there, is to cast it:

import cppyy.ll
name = cppyy.ll.cast['char16_t*'](ai.name)

which when printed, now produces hello.

Is this what you're after?

Note that there's an open bug report, with a proposed solution, to annotate what these char arrays are supposed to represent, as it is a general problem with C++ that "data" is often represented as some character type as those are easy to use with pointer arithmetic (and thus an automatic conversion has to guess the most likely use; here it was wrong): https://bitbucket.org/wlav/cppyy/issues/344/failed-to-handle-char-array-with-arbitrary

Wim Lavrijsen
  • 3,453
  • 1
  • 9
  • 21