Reputation: 30504
How do I convert between bytes
and POINTER(c_ubyte)
in Python?
I want to pass a bytes
object to a C function as a POINTER(c_ubyte)
argument, and I want to work with a returned POINTER(c_ubyte)
as bytes
.
Right now I am using:
data = b'0123'
converted_to = ctypes.cast(data, ctypes.POINTER(ctypes.c_ubyte))
converted_from = bytes(converted_to)
This doesn't seem quite right. I get a warning in PyCharm on data
in the converted_to
line that says:
Expected type 'Union[_CData, _CArgObject]', got 'bytes' instead
Upvotes: 5
Views: 5591
Reputation: 8166
Here's a simple C++ function:
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT unsigned char* DoBytesStuff(const unsigned char* buffer, size_t buffer_size)
{
const auto new_buffer = new unsigned char[buffer_size];
memcpy(new_buffer, buffer, buffer_size);
for(size_t idx = 0; idx < buffer_size; idx++)
{
new_buffer[idx] += 1;
}
return new_buffer;
}
EXTERN_DLL_EXPORT void FreeBuffer(const unsigned char* buffer)
{
delete[] buffer;
}
So basically, it takes an unsigned char*
buffer in input, copy it, add 1 to each element in the copy and returns the copied buffer.
Now for python:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ctypes
def main():
dll = ctypes.WinDLL(r"TestDll.dll")
dll.DoBytesStuff.argtypes = [ctypes.POINTER(ctypes.c_ubyte), ctypes.c_size_t]
dll.DoBytesStuff.restype = ctypes.POINTER(ctypes.c_ubyte)
dll.FreeBuffer.argtypes = [ctypes.POINTER(ctypes.c_ubyte)]
buffer = bytes(range(0x100)) # 0 to 0xff
# ctypes instance that shares the buffer of the source object; use from_buffer_copy() to not share it
# note that we must use a bytearray because bytes object are immutable (and therefore not writable).
ubuffer = (ctypes.c_ubyte * len(buffer)).from_buffer(bytearray(buffer))
result = dll.DoBytesStuff(ubuffer, len(buffer))
b_result = ctypes.string_at(result, len(buffer))
print(b_result)
dll.FreeBuffer(result)
if __name__ == "__main__":
main()
(ctypes.c_ubyte * len(buffer))
create an array of c_ubyte
which is then initialized with the from_buffer
function. from_buffer
accepts only a writable object and thus we can't use bytes
.
As for the return, string_at
directly returns a bytes
object from the pointer.
Upvotes: 4