Skip to content

[Investigation] Read string data using CLFN (and pass out string pointer separately) #3

@jimkring

Description

@jimkring

Current Approach - Read String using LabVIEW's MoveBlock functionality (before closing reference)

image

Here is the VI that reads a cstring from a memory location:

image

The MoveBlock function is exported by the LabVIEW executable app:

image

After we're done reading the data, we close the reference:

image

Different Approach - Use CLFN to Read String, but also pass string reference (so we can close reference)

A slightly different approach to reading string data from Rust is to have the CLFN read the string data (instead of just getting the address of the data and reading it with the Memory Manager). This is nice, because we can rely on LabVIEW's built in feature for reading a cstring, however, it means that we must also pass out the string's address, separately, so that we can ask Rust to deallocate/free the string after LabVIEW has read the data.

That looks something like this:

image

image

Notes:

  1. there's an additional parameter string_ptr: *mut c_void, which is how we will obtain the string pointer (in note 2 below).
  2. right before we return, we will write the return string's address to the string_ptr parameter that was passed in --> unsafe { *(string_ptr as *mut *mut c_char) = raw_string; }
// return a toml string from a Document
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn toml_edit_doc_to_string (
    doc: *mut c_void,
    string_ptr: *mut c_void,
) -> *mut c_char {
    let doc = unsafe { &mut *(doc as *mut Document) };

    let toml_str = match Document::to_string(doc) {
        toml_str => toml_str,
    };

    let raw_string = match CString::new(toml_str).unwrap().into_raw() {
        ptr if ptr.is_null() => {
            println!("Unable to allocate memory for string");
            return CString::new("").unwrap().into_raw();
        },
        ptr => ptr,
    };

    // write raw_string's address as the value stored in string_ptr
    unsafe { *(string_ptr as *mut *mut c_char) = raw_string; }
    return raw_string;
}

When we call this from LabVIEW, we can read the return string using the built in CLFN's C String Pointer format for strings.

And, we will ALSO get the address of the string as an integer that we can pass back to Rust to deallocate/free, using the cstring_free_memory() function shown below:

// exported function that frees the memory allocated for a string
// this *must* be called for every string returned from a function in this library
#[no_mangle]
pub extern "C" fn cstring_free_memory(s: *mut c_char) {
    unsafe {
        if s.is_null() {
            return;
        }
        CString::from_raw(s)
    };
}

image

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions