Reputation: 623
I'm trying to create a function that can be called from e.g. Python through a .dll.
I'm working on byte arrays. This is the original function I'm trying to wrap:
QByteArray getKeys(const QByteArray data, const QByteArray info);
What should the C style interface and implementation look like? Do I have to pass char* arrays and array sizes?
My idea is something along these lines:
__declspec(dllexport) int getKeys(const char* data, int dataSize, const char* info, int infoSize, const char** result);
The function would return the result as a side-effect and the return value is the size of the result.
Upvotes: 1
Views: 136
Reputation: 41112
Listing [Python.Docs]: ctypes - A foreign function library for Python.
@Jarod42's suggestion wasn't to use std::pair, but to emulate it via a C (compatible) struct.
Here's an example (my dummy getKeys implementation is to simply return the concatenation the 2 QByteArray arguments):
dll00.cpp:
#include <QtCore/QByteArray>
#include <cstdio>
#include <cstring>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# define DLL00_EXPORT_API
#endif
typedef struct {
size_t size = 0;
char *data = nullptr;
} CBuffer;
#if defined(__cplusplus)
extern "C" {
#endif
DLL00_EXPORT_API CBuffer getKeysWrapper(const CBuffer data, const CBuffer info);
DLL00_EXPORT_API void freeBuffer(CBuffer *pBuf);
#if defined(__cplusplus)
}
#endif
static QByteArray getKeys(const QByteArray &data, const QByteArray &info)
{
printf("C++ - data[%d]: %s\n", data.size(), data.constData());
printf("C++ - info[%d]: %s\n", info.size(), info.constData());
QByteArray ret(data);
ret += info;
printf("C++ - ret[%d]: %s\n", ret.size(), ret.constData());
return ret;
}
CBuffer getKeysWrapper(const CBuffer data, const CBuffer info)
{
QByteArray keys = getKeys(QByteArray(data.data, data.size), QByteArray(info.data, info.size));
CBuffer buf = { static_cast<size_t>(keys.size()), new char[keys.size()] };
memcpy(buf.data, keys.constData(), buf.size);
return buf;
}
void freeBuffer(CBuffer *pBuf)
{
if (!pBuf)
return;
delete[] pBuf->data;
pBuf->data = nullptr;
pBuf->size = 0;
}
code00.py:
#!/usr/bin/env python
import sys
import ctypes as ct
DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
CharPtr = ct.POINTER(ct.c_char)
class CBuffer(ct.Structure):
_fields_ = [
("size", ct.c_size_t),
("data", CharPtr),
]
def main(*argv):
dll00 = ct.CDLL(DLL_NAME)
getKeysWrapper = dll00.getKeysWrapper
getKeysWrapper.argtypes = (CBuffer, CBuffer)
getKeysWrapper.restype = CBuffer
freeBuffer = dll00.freeBuffer
freeBuffer.argtypes = (ct.POINTER(CBuffer),)
freeBuffer.restype = None
data_b = b"123456"
data_b_len = len(data_b)
info_b = b"abcd\0ef"
info_b_len = len(info_b)
data = CBuffer(data_b_len, (ct.c_char * data_b_len)(*data_b))
info = CBuffer(info_b_len, (ct.c_char * info_b_len)(*info_b))
keys = getKeysWrapper(data, info)
print("PY - keys:", keys.size, bool(keys.data), " ".join(str(keys.data[i]) for i in range(keys.size)))
freeBuffer(ct.byref(keys))
print("PY - keys(freed):", keys.size, bool(keys.data))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
Output:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q069346803]> ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> ls code00.py dll00.cpp [064bit prompt]> g++ -fPIC -DQT_NO_VERSION_TAGGING -I/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/include -shared -o dll00.so -L/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/lib dll00.cpp -lQt5Core [064bit prompt]> ls code00.py dll00.cpp dll00.so [064bit prompt]> [064bit prompt]> LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/cfati/Install/Qt/Qt/5.12.11/gcc_64/lib python code00.py Python 3.8.10 (default, Jun 2 2021, 10:49:15) [GCC 9.4.0] 064bit on linux C++ - data[6]: 123456 C++ - info[7]: abcd C++ - ret[13]: 123456abcd PY - keys: 13 True b'1' b'2' b'3' b'4' b'5' b'6' b'a' b'b' b'c' b'd' b'\x00' b'e' b'f' PY - keys(freed): 0 False Done.
Upvotes: 1