将数据缓冲区从 C++ 传递到 LabVIEW

Passing data buffers from C++ to LabVIEW

我正在尝试创建一个 LabVIEW DLL 并从 C++ 程序中调用它,但我遇到了数据传递问题。

我最近买的一台科学相机自带LabVIEW SDK,除此之外别无其他。 SDK附带的示例程序主要是一个while循环,围绕两个函数,ReadData和DecodeData。

完整示例代码:

读取数据的详细信息:

解码数据详情:

在用LabVIEW编写的示例程序中,一切正常。问题是当我在 DLL 中导出这些函数时。两个函数的内存缓冲区、输入和输出都是字符数组。在 ReadData 之后,我的 C++ 程序正确地获取了一个包含数据的缓冲区,包括空字节。

问题是当我在 DecodeData 中注入这个缓冲区时,LabVIEW 似乎只考虑第一个空字节之前的字节...我猜 char[] 输入只是作为 null-terminated 字符串,其余数据被丢弃。

我尝试添加数据转换器(输出端为“字符串到字节数组”,输入端为“字节数组到字符串”),但转换函数也会丢弃第一个空字符后的数据。

我可以将 sdk 中的 .vi 修改为只处理字节数组而不处理字符串,但它使用了很多字符处理函数,我更愿意保留它原样。

如何在不丢失部分数据的情况下将数据缓冲区从 C++ 传递到 LabVIEW DLL?

编辑:这是 C++ 代码。

用 LabVIEW DLL 导出的头文件:

int32_t __cdecl CORE_S_Read_data_from_USB(char VISARefIn[], 
    Enum1 blockToProcessPrevCycle, uint32_t bytesToProcessPrevCycle, 
    uint8_t inBytesRead[], uint32_t *BytesReceived, LVBoolean *DataReception, 
    uint8_t outBytesRead[], Enum1 *blockToProcess, uint32_t *bytesToProcess, 
    int32_t longueur, int32_t longueur2);

void __cdecl CORE_S_Decode_data(uint8_t inBytesRead[], 
    LVBoolean LUXELL256TypeB, uint32_t bytesToProcess, Enum1 blockToProcess, 
    Cluster2 *PrevHeader, LVBoolean *FrameCompleto, 
    uint32_t *bytesToProcessNextCycle, Enum1 *blockToProcessNextCycle, 
    Cluster2 *HeaderOut, uint8_t outBytesRead[], Int16Array *InfraredImage, 
    Cluster2 *Header, int32_t longueur, int32_t longueur2, int32_t longueur3);

我的 C++ 源代码中的用法:

while (...)
{
    // Append new data in uiBytesRead
    ret = CORE_S_Read_data_from_USB(VISARef, blockToProcess, bytesToProcess, uiBytesRead, &BytesReceived,
        &DataReception, uiBytesRead, &blockToProcess, &bytesToProcess, BUFFER_SIZE, BUFFER_SIZE);

    if (DataReception == 0)
        continue;

    bool FrameCompleto = true;
    while (FrameCompleto)
    {
        // Removes one frame of uiBytesRead per call
        CORE_S_Decode_data(uiBytesRead, LUXELL256TypeB, 0, blockToProcess, &Header, &FrameCompleto,  &bytesToProcess, &blockToProcess, &Header,
            uiBytesRead, &InfraredImage, &Header, BUFFER_SIZE, BUFFER_SIZE, BUFFER_SIZE);
    }
}

在这种特定情况下回答起来有点棘手,但假设问题是缓冲区数据中的 NULL 值导致问题,那么可能值得考虑使用 String Handle 的选项您正在导出的 VI 的 String-Type 控件和显示控件的指针

可以在配置 DLL 构建的“定义 VI 原型”阶段选择此选项

LabVIEW 在内部将字符串类型管理为字符串长度的整数和无符号字符数组,因此使用什么字符无关紧要。对于与外部代码的接口,LabVIEW 的 extcode.h header 定义了一个 LStrHandle 如下:

typedef struct {
    int32   cnt;        /* number of bytes that follow */
    uChar   str[1];     /* cnt bytes */
} LStr, *LStrPtr, **LStrHandle;

因此字符串句柄指针的类型为 *LStrHandle

extcode.h 提供了宏 LHStrBuf(LStrHandle)LHStrLen(LStrHandle),当您想要读取或更新字符串内容和长度时,它们可以简化对字符串句柄指针的取消引用。另外,请注意 NULL 句柄可用于表示空字符串,因此不要假设该句柄未经检查就有效。

在创建或调整字符串句柄指针的大小以传递给函数时,值得注意的是 LStr 与 LabVIEW-array 具有完全相同的 in-memory 表示形式,因此函数 NumericArrayResizetypeCode uB 可以 create/resize 一个足够大的缓冲区来存储字符串和 length-integer.

为长度为 required_string_length 的字符串创建新的字符串句柄指针的示例是通过传递 NumericArrayResize 一个句柄为 NULL 的句柄指针来实现的。

LStrHandle* new_string_handle_pointer;
// assign NULL value to handle
*new_string_handle_pointer=0;
err = NumericArrayResize(uB, 1, (UHandle *)new_string_handle_pointer, required_string_length);
// new_string_handle_pointer will now reference the new LStrHandle 

更新字符串句柄中的字符串值时,请记住将字符串的字符写入 uChar 数组 以更新大小整数。从性能的角度来看,将字符串句柄更新为较短的字符串时可能不值得缩小字符串句柄,但如果您知道要写入的字符串将超过它可以容纳的长度,则需要调整它的大小。

您应该清理从 LabVIEW 或 LabVIEW-based DLL 传递给您的任何句柄,因此一旦您完成处理,就在 handle-pointer 的句柄上调用 DSDisposeHandle参考资料。

有关LabVIEW内存管理器功能的更多信息,请阅读this guide