简体   繁体   English

如何将带有 null 字符的字符串从 C++ DLL 返回到 ZA7F5F35426B927411FC9231B56

[英]How to return a string with null characters from C++ DLL to Python?

I'm working on a Python 3 application that calls a DLL developed in C++.我正在开发一个 Python 3 应用程序,该应用程序调用在 C++ 中开发的 DLL。 The DLL reads a database record and returns the record buffer to the Python application. DLL 读取数据库记录并将记录缓冲区返回给 Python 应用程序。 The issue that I am having is that the database record may contain x'00' (null) characters.我遇到的问题是数据库记录可能包含 x'00'(空)字符。 When this occurs the record buffer that is returned to the Python application is truncated at the null character.发生这种情况时,返回到 Python 应用程序的记录缓冲区在 null 字符处被截断。

I am using memcpy to copy the record buffer to the Python return area.我正在使用memcpy将记录缓冲区复制到 Python 返回区域。 I thought memcpy copied the number of bytes specified, regardless of the content.我认为 memcpy 复制了指定的字节数,而不管内容如何。

I am not a C++ programmer, so I quite possibly could be misunderstanding how memcpy works.我不是 C++ 程序员,所以我很可能会误解 memcpy 的工作原理。

The following code snippets are examples of test code that will demonstrate the problem I am having.以下代码片段是测试代码示例,将演示我遇到的问题。

This is the DLL:这是 DLL:

#include "pch.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>     
#include <iostream>

using namespace std;

#define LIBDLL extern "C" __declspec(dllexport)

LIBDLL int readData_VPRI2(char* buffer, unsigned long buffer_length )

{
    char unsigned buf[20];
    int unsigned buf_len;
    FILE* stream;
    errno_t err;
    err = fopen_s(&stream, "D:\\testfile", "rb");
    if (err != 0) return err;
    fread(buf, buffer_length, 1, stream);
    memcpy(buffer, buf, buffer_length);
    return 0;

}

This is the Python calling routine:这是 Python 调用例程:

import ctypes
from ctypes import *

dll = ctypes.CDLL('C:\\Users\\rhkea\\source\\repos\\TestDLL\\x64\\Debug\\TestDLL.dll')

f = open("D:\\testfile", "wb")
test_string = bytes('ABCD\x00efg', encoding='utf-8')
f.write(test_string)
f.close()

char_arr = ctypes.c_char * 500                                      # set up the return area
buffer = char_arr()                                                 # assign the buffer
readData_VPRI2 = dll.readData_VPRI2                                 # get the DLL
readData_VPRI2.restype = ctypes.c_int                               # set the return type
readData_VPRI2.argtypes = (POINTER(c_char), c_long)                 # define the arguments

rc = readData_VPRI2(buffer, len(test_string))                       # call the DLL

print ("rc =", rc)
if rc==0:
    print ("buffer =", buffer.value)
    print ("buffer length = ", len(buffer.value))

The output of the Python execution is: Python执行的output为:

rc = 0
buffer = b'ABCD'
buffer length =  4

As shown, the buffer that is returned is truncated at the x'00'.如图所示,返回的缓冲区在 x'00' 处被截断。

I'm guessing there may be something simple that I am overlooking or don't understand.我猜可能有一些我忽略或不理解的简单事情。 Any guidance on how correct this problem would be greatly appreciated.任何有关如何纠正此问题的指导将不胜感激。

Thanks in advance.提前致谢。

As it turns out, the C++ code is working as designed.事实证明,C++ 代码按设计工作。 My question about memcpy is not the issue.我关于memcpy的问题不是问题。 It is working as documented.它按记录工作。

What I discovered is that Python may actually be truncating the string.我发现 Python 实际上可能正在截断字符串。 The cytpes.c_char.value returns the truncated string as described in my original question. cytpes.c_char.value返回截断的字符串,如我原来的问题中所述。

But if you use cyptes.c_char.raw the entire string (in my example, buffer ) is returned (eg, 500 bytes), padded with x'00'.但是,如果您使用cyptes.c_char.raw则返回整个字符串(在我的示例中为buffer )(例如,500 字节),并用 x'00' 填充。 So print(buffer.raw) returns:所以print(buffer.raw)返回:

b'AB\x00CDefg\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00... ...\x00'

Since I already know the length of the record I am expecting to be returned, I can simply slice it from the buffer.raw .由于我已经知道我期望返回的记录的长度,我可以简单地从buffer.raw中分割它。

Thanks for your responses.感谢您的回复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM